Completed
Push — develop ( f1ab0c...827450 )
by Gennady
18:58
created

GravityView_Edit_Entry_Render::render_edit_form()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
nc 17
nop 0
dl 0
loc 76
ccs 27
cts 27
cp 1
crap 7
rs 7.5903
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
16
class GravityView_Edit_Entry_Render {
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
	 * The View.
49
	 *
50
	 * @var \GV\View.
51
	 * @since develop
52
	 */
53
	public $view;
54
55
	/**
56
	 * Gravity Forms entry array (it won't get changed during this class lifecycle)
57
	 * @since 1.17.2
58
	 * @var array
59
	 */
60
	private static $original_entry = array();
61
62
	/**
63
	 * Gravity Forms form array (GravityView modifies the content through this class lifecycle)
64
	 *
65
	 * @var array
66
	 */
67
	public $form;
68
69
	/**
70
	 * Gravity Forms form array (it won't get changed during this class lifecycle)
71
	 * @since 1.16.2.1
72
	 * @var array
73
	 */
74
	private static $original_form;
75
76
	/**
77
	 * Gravity Forms form array after the form validation process
78
	 * @since 1.13
79
	 * @var array
80
	 */
81
	public $form_after_validation = null;
82
83
	/**
84
	 * Hold an array of GF field objects that have calculation rules
85
	 * @var array
86
	 */
87
	public $fields_with_calculation = array();
88
89
	/**
90
	 * Gravity Forms form id
91
	 *
92
	 * @var int
93
	 */
94
	public $form_id;
95
96
	/**
97
	 * ID of the current view
98
	 *
99
	 * @var int
100
	 */
101
	public $view_id;
102
103
	/**
104
	 * ID of the current post. May also be ID of the current View.
105
     *
106
     * @since 2.0.13
107
     * 
108
     * @var int
109
	 */
110
	public $post_id;
111
112
	/**
113
	 * Updated entry is valid (GF Validation object)
114
	 *
115
	 * @var array
116
	 */
117
	public $is_valid = NULL;
118
119 18
	/**
120 18
	 * Internal page button states.
121 18
	 *
122
	 * @var bool
123 18
	 *
124
	 * @since develop
125
	 */
126 18
	public $show_previous_button;
127
	public $show_next_button;
128
	public $show_update_button;
129 18
130 18
	function __construct( GravityView_Edit_Entry $loader ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
131
		$this->loader = $loader;
132
	}
133 18
134
	function load() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
135 18
136
		/** @define "GRAVITYVIEW_DIR" "../../../" */
137 18
		include_once( GRAVITYVIEW_DIR .'includes/class-admin-approve-entries.php' );
138
139
		// Don't display an embedded form when editing an entry
140 18
		add_action( 'wp_head', array( $this, 'prevent_render_form' ) );
141
		add_action( 'wp_footer', array( $this, 'prevent_render_form' ) );
142
143 18
		// Stop Gravity Forms processing what is ours!
144
		add_filter( 'wp', array( $this, 'prevent_maybe_process_form'), 8 );
145
146 18
		add_filter( 'gravityview_is_edit_entry', array( $this, 'is_edit_entry') );
147
148
		add_action( 'gravityview_edit_entry', array( $this, 'init' ), 10, 4 );
149 18
150 18
		// Disable conditional logic if needed (since 1.9)
151
		add_filter( 'gform_has_conditional_logic', array( $this, 'manage_conditional_logic' ), 10, 2 );
152
153
		// Make sure GF doesn't validate max files (since 1.9)
154
		add_filter( 'gform_plupload_settings', array( $this, 'modify_fileupload_settings' ), 10, 3 );
155
156
		// Add fields expected by GFFormDisplay::validate()
157
		add_filter( 'gform_pre_validation', array( $this, 'gform_pre_validation') );
158
159
		// Fix multiselect value for GF 2.2
160
		add_filter( 'gravityview/edit_entry/field_value_multiselect', array( $this, 'fix_multiselect_value_serialization' ), 10, 3 );
161
	}
162 1
163 1
	/**
164 1
	 * Don't show any forms embedded on a page when GravityView is in Edit Entry mode
165 1
	 *
166
	 * Adds a `__return_empty_string` filter on the Gravity Forms shortcode on the `wp_head` action
167 1
	 * And then removes it on the `wp_footer` action
168
	 *
169
	 * @since 1.16.1
170 1
	 *
171
	 * @return void
172
	 */
173
	public function prevent_render_form() {
174
		if( $this->is_edit_entry() ) {
175
			if( 'wp_head' === current_filter() ) {
176
				add_filter( 'gform_shortcode_form', '__return_empty_string' );
177 1
			} else {
178
				remove_filter( 'gform_shortcode_form', '__return_empty_string' );
179 1
			}
180 1
		}
181
	}
182
183
	/**
184
	 * Because we're mimicking being a front-end Gravity Forms form while using a Gravity Forms
185
	 * backend form, we need to prevent them from saving twice.
186
	 * @return void
187
	 */
188
	public function prevent_maybe_process_form() {
189
190
	    if( ! $this->is_edit_entry_submission() ) {
191
			return;
192
		}
193 23
194
		gravityview()->log->debug( 'GravityView_Edit_Entry[prevent_maybe_process_form] Removing GFForms::maybe_process_form() action.' );
195 23
196
		remove_action( 'wp',  array( 'RGForms', 'maybe_process_form'), 9 );
197 23
		remove_action( 'wp',  array( 'GFForms', 'maybe_process_form'), 9 );
198
	}
199
200
	/**
201
	 * Is the current page an Edit Entry page?
202
	 * @return boolean
203
	 */
204
	public function is_edit_entry() {
205 23
206 23
		$is_edit_entry = GravityView_frontend::is_single_entry() && ! empty( $_GET['edit'] );
207
208
		return ( $is_edit_entry || $this->is_edit_entry_submission() );
209
	}
210
211
	/**
212 18
	 * Is the current page an Edit Entry page?
213 18
	 * @since 1.9
214
	 * @return boolean
215 18
	 */
216
	public function is_edit_entry_submission() {
217
		return !empty( $_POST[ self::$nonce_field ] );
218 18
	}
219 18
220 18
	/**
221
	 * When Edit entry view is requested setup the vars
222 18
	 */
223 18
	private function setup_vars() {
224 18
        global $post;
225 18
226 18
		$gravityview_view = GravityView_View::getInstance();
227
228 18
229 18
		$entries = $gravityview_view->getEntries();
230
	    self::$original_entry = $entries[0];
231
	    $this->entry = $entries[0];
232
233
		self::$original_form = $gravityview_view->getForm();
234
		$this->form = $gravityview_view->getForm();
235
		$this->form_id = $this->entry['form_id'];
236
		$this->view_id = $gravityview_view->getViewId();
237
		$this->post_id = \GV\Utils::get( $post, 'ID', null );
238
239
		self::$nonce_key = GravityView_Edit_Entry::get_nonce_key( $this->view_id, $this->form_id, $this->entry['id'] );
240
	}
241
242
243
	/**
244
	 * Load required files and trigger edit flow
245
	 *
246 19
	 * Run when the is_edit_entry returns true.
247
	 *
248 19
	 * @param \GravityView_View_Data $gv_data GravityView Data object
249 19
	 * @param \GV\Entry   $entry   The Entry.
250
	 * @param \GV\View    $view    The View.
251 19
	 * @param \GV\Request $request The Request.
252
	 *
253 19
	 * @since develop Added $entry, $view, $request adhocs.
254
	 *
255
	 * @return void
256
	 */
257
	public function init( $gv_data = null, $entry = null, $view = null, $request = null ) {
258 19
259
		require_once( GFCommon::get_base_path() . '/form_display.php' );
260
		require_once( GFCommon::get_base_path() . '/entry_detail.php' );
261
262
		$this->setup_vars();
263
264 19
		if ( ! $gv_data ) {
265 1
			$gv_data = GravityView_View_Data::getInstance();
266 1
		}
267
268
		// Multiple Views embedded, don't proceed if nonce fails
269 19
		if ( $gv_data->has_multiple_views() && ! $this->verify_nonce() ) {
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_View_Data::has_multiple_views() has been deprecated.

This method has been deprecated.

Loading history...
270
			gravityview()->log->error( 'Nonce validation failed for the Edit Entry request; returning' );
271 19
			return;
272
		}
273 19
274
		// Sorry, you're not allowed here.
275 19
		if ( false === $this->user_can_edit_entry( true ) ) {
276
			gravityview()->log->error( 'User is not allowed to edit this entry; returning', array( 'data' => $this->entry ) );
277 19
			return;
278
		}
279
280
		$this->view = $view;
281
282
		$this->print_scripts();
283
284 18
		$this->process_save( $gv_data );
285 18
286
		$this->edit_entry_form();
287 18
288
	}
289 18
290
291 18
	/**
292
	 * Force Gravity Forms to output scripts as if it were in the admin
293
	 * @return void
294 18
	 */
295 18
	private function print_scripts() {
296
		$gravityview_view = GravityView_View::getInstance();
297
298
		wp_register_script( 'gform_gravityforms', GFCommon::get_base_url().'/js/gravityforms.js', array( 'jquery', 'gform_json', 'gform_placeholder', 'sack', 'plupload-all', 'gravityview-fe-view' ) );
299
300
		GFFormDisplay::enqueue_form_scripts( $gravityview_view->getForm(), false);
301
302
		wp_localize_script( 'gravityview-fe-view', 'gvGlobals', array( 'cookiepath' => COOKIEPATH ) );
303 19
304
		// Sack is required for images
305 19
		wp_print_scripts( array( 'sack', 'gform_gravityforms', 'gravityview-fe-view' ) );
306 5
	}
307
308
309
	/**
310 18
	 * Process edit entry form save
311
	 *
312 18
	 * @param array $gv_data The View data.
313
	 */
314
	private function process_save( $gv_data ) {
315
316
		if ( empty( $_POST ) || ! isset( $_POST['lid'] ) ) {
317 18
			return;
318
		}
319
320
		// Make sure the entry, view, and form IDs are all correct
321
		$valid = $this->verify_nonce();
322 18
323
		if ( !$valid ) {
324 18
			gravityview()->log->error( 'Nonce validation failed.' );
325
			return;
326 18
		}
327
328 18
		if ( $this->entry['id'] !== $_POST['lid'] ) {
329
			gravityview()->log->error( 'Entry ID did not match posted entry ID.' );
330 18
			return;
331
		}
332
333
		gravityview()->log->debug( '$_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
334
335 18
		$this->process_save_process_files( $this->form_id );
336
337
		$this->validate();
338
339
		if( $this->is_valid ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_valid of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
340 18
341
			gravityview()->log->debug( 'Submission is valid.' );
342 18
343
			/**
344
			 * @hack This step is needed to unset the adminOnly from form fields, to add the calculation fields
345
			 */
346
			$form = $this->form_prepare_for_save();
347
348 18
			/**
349
			 * @hack to avoid the capability validation of the method save_lead for GF 1.9+
350
			 */
351
			unset( $_GET['page'] );
352
353
			$date_created = $this->entry['date_created'];
354
355
			/**
356
			 * @hack to force Gravity Forms to use $read_value_from_post in GFFormsModel::save_lead()
357
			 * @since 1.17.2
358 18
			 */
359
			unset( $this->entry['date_created'] );
360 18
361
			/**
362
			 * @action `gravityview/edit_entry/before_update` Perform an action after the entry has been updated using Edit Entry
363 18
			 * @since develop
364
			 * @param array $form Gravity Forms form array
365 18
			 * @param string $entry_id Numeric ID of the entry that is being updated
366
			 * @param GravityView_Edit_Entry_Render $this This object
367
			 * @param GravityView_View_Data $gv_data The View data
368 18
			 */
369
			do_action( 'gravityview/edit_entry/before_update', $form, $this->entry['id'], $this, $gv_data );
370
371 18
			GFFormsModel::save_lead( $form, $this->entry );
372
373
	        // Delete the values for hidden inputs
374
	        $this->unset_hidden_field_values();
375
			
376
			$this->entry['date_created'] = $date_created;
377 18
378
			// Process calculation fields
379
			$this->update_calculation_fields();
380
381
			// Perform actions normally performed after updating a lead
382
			$this->after_update();
383
384
	        /**
385
			 * Must be AFTER after_update()!
386
			 * @see https://github.com/gravityview/GravityView/issues/764
387 18
			 */
388
			$this->maybe_update_post_fields( $form );
389
390
			/**
391
			 * @action `gravityview/edit_entry/after_update` Perform an action after the entry has been updated using Edit Entry
392
             * @since 2.1 Added $gv_data parameter
393 18
			 * @param array $form Gravity Forms form array
394
			 * @param string $entry_id Numeric ID of the entry that was updated
395
			 * @param GravityView_Edit_Entry_Render $this This object
396
			 * @param GravityView_View_Data $gv_data The View data
397
			 */
398
			do_action( 'gravityview/edit_entry/after_update', $this->form, $this->entry['id'], $this, $gv_data );
399
400
		} else {
401
			gravityview()->log->error( 'Submission is NOT valid.', array( 'entry' => $this->entry ) );
402
		}
403
404 17
	} // process_save
405 17
406
	/**
407
	 * Delete the value of fields hidden by conditional logic when the entry is edited
408
	 *
409
	 * @uses GFFormsModel::update_lead_field_value()
410
	 *
411
	 * @since 1.17.4
412
	 *
413 17
	 * @return void
414
	 */
415 17
	private function unset_hidden_field_values() {
416
	    global $wpdb;
417 17
418
		/**
419
		 * @filter `gravityview/edit_entry/unset_hidden_field_values` Whether to delete values of fields hidden by conditional logic
420
		 * @since 1.22.2
421 17
		 * @param bool $unset_hidden_field_values Default: true
422 17
		 * @param GravityView_Edit_Entry_Render $this This object
423 17
		 */
424
		$unset_hidden_field_values = apply_filters( 'gravityview/edit_entry/unset_hidden_field_values', true, $this );
425
426
		$this->unset_hidden_calculations = array();
0 ignored issues
show
Bug introduced by
The property unset_hidden_calculations does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
427
428
		if( ! $unset_hidden_field_values ) {
429 17
			return;
430
		}
431 17
432 17
		if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
433
			$entry_meta_table = GFFormsModel::get_entry_meta_table_name();
434
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $entry_meta_table WHERE entry_id=%d", $this->entry['id'] ) );
435 17
		} else {
436
			$lead_detail_table = GFFormsModel::get_lead_details_table_name();
437
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $lead_detail_table WHERE lead_id=%d", $this->entry['id'] ) );
438
		}
439 17
440
	    foreach ( $this->entry as $input_id => $field_value ) {
441 1
442 1
			if ( ! is_numeric( $input_id ) ) {
443 1
				continue;
444
			}
445
446 1
		    $field = RGFormsModel::get_field( $this->form, $input_id );
447 1
448 1
		    // Reset fields that are hidden
449
		    // Don't pass $entry as fourth parameter; force using $_POST values to calculate conditional logic
450
		    if ( GFFormsModel::is_field_hidden( $this->form, $field, array(), NULL ) ) {
451 1
452
				$empty_value = $field->get_value_save_entry(
453 1
					is_array( $field->get_entry_inputs() ) ? array() : '',
454
					$this->form, '', $this->entry['id'], $this->entry
455
				);
456
457 1
				if ( $field->has_calculation() ) {
458 1
					$this->unset_hidden_calculations[] = $field->id; // Unset
459
					$empty_value = '';
460
				}
461 17
462
			    $lead_detail_id = GFFormsModel::get_lead_detail_id( $current_fields, $input_id );
463
464
			    GFFormsModel::update_lead_field_value( $this->form, $this->entry, $field, $lead_detail_id, $input_id, $empty_value );
465
466
			    // Prevent the $_POST values of hidden fields from being used as default values when rendering the form
467
				// after submission
468
			    $post_input_id = 'input_' . str_replace( '.', '_', $input_id );
469
			    $_POST[ $post_input_id ] = '';
470 17
		    }
471
	    }
472
	}
473 17
474 17
	/**
475 16
	 * Have GF handle file uploads
476
	 *
477
	 * Copy of code from GFFormDisplay::process_form()
478
	 *
479
	 * @param int $form_id
480
	 */
481
	private function process_save_process_files( $form_id ) {
482 17
483
		//Loading files that have been uploaded to temp folder
484 17
		$files = GFCommon::json_decode( stripslashes( RGForms::post( 'gform_uploaded_files' ) ) );
485 17
		if ( ! is_array( $files ) ) {
486
			$files = array();
487
		}
488
489
		/**
490
		 * Make sure the fileuploads are not overwritten if no such request was done.
491
		 * @since 1.20.1
492
		 */
493
		add_filter( "gform_save_field_value_$form_id", array( $this, 'save_field_value' ), 99, 5 );
494
495
		RGFormsModel::$uploaded_files[ $form_id ] = $files;
496
	}
497
498
	/**
499
	 * Make sure the fileuploads are not overwritten if no such request was done.
500
	 *
501
	 * TO ONLY BE USED INTERNALLY; DO NOT DEVELOP ON; MAY BE REMOVED AT ANY TIME.
502 17
	 *
503
	 * @since 1.20.1
504 17
	 *
505 17
	 * @param string $value Field value
506
	 * @param array $entry GF entry array
507
	 * @param GF_Field_FileUpload $field
508 1
	 * @param array $form GF form array
509
	 * @param string $input_id ID of the input being saved
510 1
	 *
511
	 * @return string
512
	 */
513
	public function save_field_value( $value = '', $entry = array(), $field = null, $form = array(), $input_id = '' ) {
514
515
		if ( ! $field || $field->type != 'fileupload' ) {
516
			return $value;
517
		}
518 1
519
		$input_name = 'input_' . str_replace( '.', '_', $input_id );
520 1
521
		if ( $field->multipleFiles ) {
522
			if ( empty( $value ) ) {
523 1
				return json_decode( $entry[ $input_id ], true );
524
			}
525
			return $value;
526
		}
527
528
		/** No file is being uploaded. */
529
		if ( empty( $_FILES[ $input_name ]['name'] ) ) {
530
			/** So return the original upload */
531
			return $entry[ $input_id ];
532
		}
533
534
		return $value;
535 2
	}
536 2
537
	/**
538
	 * Remove max_files validation (done on gravityforms.js) to avoid conflicts with GravityView
539
	 * Late validation done on self::custom_validation
540 2
	 *
541
	 * @param $plupload_init array Plupload settings
542 2
	 * @param $form_id
543
	 * @param $instance
544
	 * @return mixed
545
	 */
546
	public function modify_fileupload_settings( $plupload_init, $form_id, $instance ) {
0 ignored issues
show
Unused Code introduced by
The parameter $form_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $instance is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
547
		if( ! $this->is_edit_entry() ) {
548
			return $plupload_init;
549
		}
550 17
551
		$plupload_init['gf_vars']['max_files'] = 0;
552 17
553
		return $plupload_init;
554
	}
555 17
556
557
	/**
558
	 * Set visibility to visible and convert field input key to string
559
	 * @return array $form
560
	 */
561
	private function form_prepare_for_save() {
562 17
563 4
		$form = $this->filter_conditional_logic( $this->form );
564
565
	    /** @var GF_Field $field */
566 17
		foreach( $form['fields'] as $k => &$field ) {
567
568 17
			/**
569 2
			 * Remove the fields with calculation formulas before save to avoid conflicts with GF logic
570 2
			 * @since 1.16.3
571
			 * @var GF_Field $field
572
			 */
573
			if( $field->has_calculation() ) {
574
				unset( $form['fields'][ $k ] );
575 17
			}
576
577 17
			$field->adminOnly = false;
578
579
			if( isset( $field->inputs ) && is_array( $field->inputs ) ) {
580 17
				foreach( $field->inputs as $key => $input ) {
581 17
				    $field->inputs[ $key ][ 'id' ] = (string)$input['id'];
582
				}
583 17
			}
584 17
		}
585
586
		$form['fields'] = array_values( $form['fields'] );
587 17
588
		return $form;
589 17
	}
590 17
591 17
	private function update_calculation_fields() {
592
		global $wpdb;
593
594
		$form = self::$original_form;
595
		$update = false;
596
597
		// get the most up to date entry values
598 17
		$entry = GFAPI::get_entry( $this->entry['id'] );
599 5
600 5
		if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
601
			$entry_meta_table = GFFormsModel::get_entry_meta_table_name();
602 5
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $entry_meta_table WHERE entry_id=%d", $entry['id'] ) );
603
		} else {
604 5
			$lead_detail_table = GFFormsModel::get_lead_details_table_name();
605 1
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $lead_detail_table WHERE lead_id=%d", $entry['id'] ) );
606
		}
607
608 5
609 5
		if ( ! empty( $this->fields_with_calculation ) ) {
610 4
			$allowed_fields = $this->get_configured_edit_fields( $form, $this->view_id );
611 4
			$allowed_fields = wp_list_pluck( $allowed_fields, 'id' );
612
613 4
			foreach ( $this->fields_with_calculation as $field ) {
614 4
615
				if ( in_array( $field->id, $this->unset_hidden_calculations, true ) ) {
616
					continue;
617 4
				}
618
619 4
				$inputs = $field->get_entry_inputs();
620
				if ( is_array( $inputs ) ) {
621
				    foreach ( $inputs as $input ) {
622
						list( $field_id, $input_id ) = rgexplode( '.', $input['id'], 2 );
623
624
						if ( 'product' === $field->type ) {
625
							$input_name = 'input_' . str_replace( '.', '_', $input['id'] );
626
627
							// Only allow quantity to be set if it's allowed to be edited
628 4
							if ( in_array( $field_id, $allowed_fields ) && $input_id == 3 ) {
629
							} else { // otherwise set to what it previously was
630
								$_POST[ $input_name ] = $entry[ $input['id'] ];
631
							}
632 3
						} else {
633 2
							// Set to what it previously was if it's not editable
634
							if ( ! in_array( $field_id, $allowed_fields ) ) {
635 3
								$_POST[ $input_name ] = $entry[ $input['id'] ];
0 ignored issues
show
Bug introduced by
The variable $input_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
636
							}
637
						}
638
639 5
						GFFormsModel::save_input( $form, $field, $entry, $current_fields, $input['id'] );
640 5
				    }
641
				} else {
642
					// Set to what it previously was if it's not editable
643 17
					if ( ! in_array( $field->id, $allowed_fields ) ) {
644
						$_POST[ 'input_' . $field->id ] = $entry[ $field->id ];
645
					}
646
					GFFormsModel::save_input( $form, $field, $entry, $current_fields, $field->id );
647
				}
648
			}
649
650
			if ( method_exists( 'GFFormsModel', 'commit_batch_field_operations' ) ) {
651
				GFFormsModel::commit_batch_field_operations();
652
			}
653
		}
654
	}
655
656
	/**
657
	 * Handle updating the Post Image field
658
	 *
659
	 * Sets a new Featured Image if configured in Gravity Forms; otherwise uploads/updates media
660
	 *
661
	 * @since 1.17
662
	 *
663
	 * @uses GFFormsModel::media_handle_upload
664 1
	 * @uses set_post_thumbnail
665
	 *
666 1
	 * @param array $form GF Form array
667
	 * @param GF_Field $field GF Field
668 1
	 * @param string $field_id Numeric ID of the field
669
	 * @param string $value
670
	 * @param array $entry GF Entry currently being edited
671
	 * @param int $post_id ID of the Post being edited
672
	 *
673
	 * @return mixed|string
674
	 */
675
	private function update_post_image( $form, $field, $field_id, $value, $entry, $post_id ) {
676
677
		$input_name = 'input_' . $field_id;
678
679
		if ( !empty( $_FILES[ $input_name ]['name'] ) ) {
680
681
			// We have a new image
682
683
			$value = RGFormsModel::prepare_value( $form, $field, $value, $input_name, $entry['id'] );
684
685
			$ary = ! empty( $value ) ? explode( '|:|', $value ) : array();
686
	        $ary = stripslashes_deep( $ary );
687
			$img_url = \GV\Utils::get( $ary, 0 );
688
689
			$img_title       = count( $ary ) > 1 ? $ary[1] : '';
690
			$img_caption     = count( $ary ) > 2 ? $ary[2] : '';
691
			$img_description = count( $ary ) > 3 ? $ary[3] : '';
692
693
			$image_meta = array(
694
				'post_excerpt' => $img_caption,
695
				'post_content' => $img_description,
696
			);
697
698
			//adding title only if it is not empty. It will default to the file name if it is not in the array
699
			if ( ! empty( $img_title ) ) {
700
				$image_meta['post_title'] = $img_title;
701
			}
702
703
			/**
704 1
			 * 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.
705
			 * Note: the method became public in GF 1.9.17.7, but we don't require that version yet.
706 1
			 */
707 1
			require_once GRAVITYVIEW_DIR . 'includes/class-gravityview-gfformsmodel.php';
708 1
			$media_id = GravityView_GFFormsModel::media_handle_upload( $img_url, $post_id, $image_meta );
709 1
710
			// is this field set as featured image?
711 1
			if ( $media_id && $field->postFeaturedImage ) {
712
				set_post_thumbnail( $post_id, $media_id );
713 1
			}
714
715
		} elseif ( ! empty( $_POST[ $input_name ] ) && is_array( $value ) ) {
716 1
717 1
			$img_url         = stripslashes_deep( $_POST[ $input_name ] );
718 1
			$img_title       = stripslashes_deep( \GV\Utils::_POST( $input_name . '_1' ) );
719 1
			$img_caption     = stripslashes_deep( \GV\Utils::_POST( $input_name . '_4' ) );
720
			$img_description = stripslashes_deep( \GV\Utils::_POST( $input_name . '_7' ) );
721
722
			$value = ! empty( $img_url ) ? $img_url . "|:|" . $img_title . "|:|" . $img_caption . "|:|" . $img_description : '';
723 1
724
			if ( $field->postFeaturedImage ) {
725
726
				$image_meta = array(
727
					'ID' => get_post_thumbnail_id( $post_id ),
728
					'post_title' => $img_title,
729
					'post_excerpt' => $img_caption,
730
					'post_content' => $img_description,
731
				);
732
733
				// update image title, caption or description
734
				wp_update_post( $image_meta );
735 1
			}
736
		} else {
737
738
			// if we get here, image was removed or not set.
739
			$value = '';
740
741
			if ( $field->postFeaturedImage ) {
742
				delete_post_thumbnail( $post_id );
743
			}
744
		}
745 17
746
		return $value;
747 17
	}
748 16
749 16
	/**
750
	 * Loop through the fields being edited and if they include Post fields, update the Entry's post object
751
	 *
752 1
	 * @param array $form Gravity Forms form
753
	 *
754
	 * @return void
755 1
	 */
756
	private function maybe_update_post_fields( $form ) {
757
758
		if( empty( $this->entry['post_id'] ) ) {
759
	        gravityview()->log->debug( 'This entry has no post fields. Continuing...' );
760 1
			return;
761
		}
762 1
763
		$post_id = $this->entry['post_id'];
764 1
765
		// Security check
766 1
		if( false === GVCommon::has_cap( 'edit_post', $post_id ) ) {
767
			gravityview()->log->error( 'The current user does not have the ability to edit Post #{post_id}', array( 'post_id' => $post_id ) );
768 1
			return;
769 1
		}
770
771
		$update_entry = false;
772 1
773
		$updated_post = $original_post = get_post( $post_id );
774
775 1
		foreach ( $this->entry as $field_id => $value ) {
776
777
			$field = RGFormsModel::get_field( $form, $field_id );
778 1
779 1
			if( ! $field ) {
780
				continue;
781 1
			}
782
783 1
			if( GFCommon::is_post_field( $field ) && 'post_category' !== $field->type ) {
784
785
				// Get the value of the field, including $_POSTed value
786
				$value = RGFormsModel::get_field_value( $field );
787
788
				// Use temporary entry variable, to make values available to fill_post_template() and update_post_image()
789
				$entry_tmp = $this->entry;
790
				$entry_tmp["{$field_id}"] = $value;
791
792
				switch( $field->type ) {
793 1
794
				    case 'post_title':
795
				        $post_title = $value;
796
				        if ( \GV\Utils::get( $form, 'postTitleTemplateEnabled' ) ) {
797
				            $post_title = $this->fill_post_template( $form['postTitleTemplate'], $form, $entry_tmp );
798
				        }
799
				        $updated_post->post_title = $post_title;
800
				        $updated_post->post_name  = $post_title;
801 1
				        unset( $post_title );
802
				        break;
803
804 1
				    case 'post_content':
805
				        $post_content = $value;
806
				        if ( \GV\Utils::get( $form, 'postContentTemplateEnabled' ) ) {
807 1
				            $post_content = $this->fill_post_template( $form['postContentTemplate'], $form, $entry_tmp, true );
808
				        }
809 1
				        $updated_post->post_content = $post_content;
810
				        unset( $post_content );
811
				        break;
812
				    case 'post_excerpt':
813
				        $updated_post->post_excerpt = $value;
814
				        break;
815
				    case 'post_tags':
816
				        wp_set_post_tags( $post_id, $value, false );
817
				        break;
818
				    case 'post_category':
819
				        break;
820
				    case 'post_custom_field':
821
						if ( is_array( $value ) && ( floatval( $field_id ) !== floatval( $field->id ) ) ) {
822
							$value = $value[ $field_id ];
823 1
						}
824 1
825 1
				        if( ! empty( $field->customFieldTemplateEnabled ) ) {
826
				            $value = $this->fill_post_template( $field->customFieldTemplate, $form, $entry_tmp, true );
827
				        }
828
829
						$value = $field->get_value_save_entry( $value, $form, '', $this->entry['id'], $this->entry );
830 1
831
				        update_post_meta( $post_id, $field->postCustomFieldName, $value );
832 1
				        break;
833
834 1
				    case 'post_image':
835
				        $value = $this->update_post_image( $form, $field, $field_id, $value, $this->entry, $post_id );
836
				        break;
837
838
				}
839 1
840
				// update entry after
841 1
				$this->entry["{$field_id}"] = $value;
842
843 1
				$update_entry = true;
844
845
				unset( $entry_tmp );
846 1
			}
847
848
		}
849
850
		if( $update_entry ) {
851 1
852
			$return_entry = GFAPI::update_entry( $this->entry );
853 1
854
			if( is_wp_error( $return_entry ) ) {
855
				gravityview()->log->error( 'Updating the entry post fields failed', array( 'data' => array( '$this->entry' => $this->entry, '$return_entry' => $return_entry ) ) );
856
			} else {
857 1
				gravityview()->log->debug( 'Updating the entry post fields for post #{post_id} succeeded', array( 'post_id' => $post_id ) );
858
			}
859 1
860
		}
861
862
		$return_post = wp_update_post( $updated_post, true );
863
864
		if( is_wp_error( $return_post ) ) {
865
			$return_post->add_data( $updated_post, '$updated_post' );
866
			gravityview()->log->error( 'Updating the post content failed', array( 'data' => compact( 'updated_post', 'return_post' ) ) );
867
		} else {
868
			gravityview()->log->debug( 'Updating the post content for post #{post_id} succeeded', array( 'post_id' => $post_id, 'data' => $updated_post ) );
869
		}
870
	}
871
872
	/**
873
	 * Convert a field content template into prepared output
874
	 *
875
	 * @uses GravityView_GFFormsModel::get_post_field_images()
876
	 *
877
	 * @since 1.17
878
	 *
879
	 * @param string $template The content template for the field
880
	 * @param array $form Gravity Forms form
881
	 * @param bool $do_shortcode Whether to process shortcode inside content. In GF, only run on Custom Field and Post Content fields
882
	 *
883
	 * @return string
884
	 */
885
	private function fill_post_template( $template, $form, $entry, $do_shortcode = false ) {
886
887
		require_once GRAVITYVIEW_DIR . 'includes/class-gravityview-gfformsmodel.php';
888
889
		$post_images = GravityView_GFFormsModel::get_post_field_images( $form, $entry );
890
891
		//replacing post image variables
892
		$output = GFCommon::replace_variables_post_image( $template, $post_images, $entry );
893
894
		//replacing all other variables
895
		$output = GFCommon::replace_variables( $output, $form, $entry, false, false, false );
896
897
		// replace conditional shortcodes
898
		if( $do_shortcode ) {
899
			$output = do_shortcode( $output );
900
		}
901
902
		return $output;
903
	}
904 17
905
906 17
	/**
907 17
	 * Perform actions normally performed after updating a lead
908
	 *
909
	 * @since 1.8
910 17
	 *
911
	 * @see GFEntryDetail::lead_detail_page()
912 17
	 *
913
	 * @return void
914 17
	 */
915
	private function after_update() {
916
917
		do_action( 'gform_after_update_entry', $this->form, $this->entry['id'], self::$original_entry );
918
		do_action( "gform_after_update_entry_{$this->form['id']}", $this->form, $this->entry['id'], self::$original_entry );
919
920
		// Re-define the entry now that we've updated it.
921
		$entry = RGFormsModel::get_lead( $this->entry['id'] );
922
923
		$entry = GFFormsModel::set_entry_meta( $entry, self::$original_form );
924
925
		if ( version_compare( GFFormsModel::get_database_version(), '2.3-dev-1', '<' ) ) {
926
			// We need to clear the cache because Gravity Forms caches the field values, which
927 17
			// we have just updated.
928 1
			foreach ($this->form['fields'] as $key => $field) {
929 1
				GFFormsModel::refresh_lead_field_value( $entry['id'], $field->id );
930 1
			}
931 1
		}
932 1
933 1
		/**
934 1
		 * Maybe process feeds.
935 1
		 *
936
		 * @since develop
937
		 */
938
		if ( $allowed_feeds = $this->view->settings->get( 'edit_feeds', array() ) ) {
939 1
			$feeds = GFAPI::get_feeds( null, $entry['form_id'] );
940 1
			if ( ! is_wp_error( $feeds ) ) {
941 1
				$registered_feeds = array();
942 1
				foreach ( GFAddOn::get_registered_addons() as $registered_feed ) {
943 1
					if ( is_subclass_of( $registered_feed,  'GFFeedAddOn' ) ) {
944
						if ( method_exists( $registered_feed, 'get_instance' ) ) {
945
							$registered_feed = call_user_func( array( $registered_feed, 'get_instance' ) );
946
							$registered_feeds[ $registered_feed->get_slug() ] = $registered_feed;
947 1
						}
948 1
					}
949 1
				}
950
				foreach ( $feeds as $feed ) {
951
					if ( in_array( $feed['id'], $allowed_feeds ) ) {
952
						if ( $feed_object = \GV\Utils::get( $registered_feeds, $feed['addon_slug'] ) ) {
953
							$returned_entry = $feed_object->process_feed( $feed, $entry, self::$original_form );
954
							if ( is_array( $returned_entry ) && rgar( $returned_entry, 'id' ) ) {
955
								$entry = $returned_entry;
956 17
							}
957 17
958
							do_action( 'gform_post_process_feed', $feed, $entry, self::$original_form, $feed_object );
959
							$slug = $feed_object->get_slug();
960
							do_action( "gform_{$slug}_post_process_feed", $feed, $entry, self::$original_form, $feed_object );
961
						}
962
					}
963
				}
964
			}
965 18
		}
966
967
		$this->entry = $entry;
968
	}
969
970
971 18
	/**
972
	 * Display the Edit Entry form
973
	 *
974
	 * @return void
975
	 */
976
	public function edit_entry_form() {
977 18
978
		?>
979
980
		<div class="gv-edit-entry-wrapper"><?php
981
982
			$javascript = gravityview_ob_include( GravityView_Edit_Entry::$file .'/partials/inline-javascript.php', $this );
0 ignored issues
show
Bug introduced by
The property file cannot be accessed from this context as it is declared private in class GravityView_Edit_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
983
984
			/**
985
			 * Fixes weird wpautop() issue
986
			 * @see https://github.com/katzwebservices/GravityView/issues/451
987 18
			 */
988
			echo gravityview_strip_whitespace( $javascript );
989 18
990
			?><h2 class="gv-edit-entry-title">
991
				<span><?php
992
993
				    /**
994
				     * @filter `gravityview_edit_entry_title` Modify the edit entry title
995
				     * @param string $edit_entry_title Modify the "Edit Entry" title
996
				     * @param GravityView_Edit_Entry_Render $this This object
997
				     */
998
				    $edit_entry_title = apply_filters('gravityview_edit_entry_title', __('Edit Entry', 'gravityview'), $this );
999
1000
				    echo esc_attr( $edit_entry_title );
1001 18
			?></span>
1002
			</h2>
1003 18
1004
			<?php $this->maybe_print_message(); ?>
1005
1006 18
			<?php // The ID of the form needs to be `gform_{form_id}` for the pluploader ?>
1007
1008
			<form method="post" id="gform_<?php echo $this->form_id; ?>" enctype="multipart/form-data">
1009 18
1010
				<?php
1011
1012
				wp_nonce_field( self::$nonce_key, self::$nonce_key );
1013
1014
				wp_nonce_field( self::$nonce_field, self::$nonce_field, false );
1015
1016
				// Print the actual form HTML
1017
				$this->render_edit_form();
1018
1019
				?>
1020 18
			</form>
1021
1022
			<script>
1023
				gform.addFilter('gform_reset_pre_conditional_logic_field_action', function ( reset, formId, targetId, defaultValues, isInit ) {
1024
				    return false;
1025
				});
1026
			</script>
1027
1028
		</div>
1029
1030
	<?php
1031 18
	}
1032
1033 18
	/**
1034
	 * Display success or error message if the form has been submitted
1035 17
	 *
1036
	 * @uses GVCommon::generate_notice
1037 17
	 *
1038
	 * @since 1.16.2.2
1039
	 *
1040
	 * @return void
1041
	 */
1042
	private function maybe_print_message() {
1043
1044
		if ( \GV\Utils::_POST( 'action' ) === 'update' ) {
1045
1046 17
			$back_link = remove_query_arg( array( 'page', 'view', 'edit' ) );
1047 17
1048 17
			if( ! $this->is_valid ){
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_valid of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1049
1050
				// Keeping this compatible with Gravity Forms.
1051
				$validation_message = "<div class='validation_error'>" . __('There was a problem with your submission.', 'gravityview') . " " . __('Errors have been highlighted below.', 'gravityview') . "</div>";
1052 17
				$message = apply_filters("gform_validation_message_{$this->form['id']}", apply_filters("gform_validation_message", $validation_message, $this->form), $this->form);
1053 1
1054 1
				echo GVCommon::generate_notice( $message , 'gv-error' );
1055 1
1056
			} else {
1057 16
				$view = \GV\View::by_id( $this->view_id );
1058 1
				$edit_redirect = $view->settings->get( 'edit_redirect' );
1059 1
				$edit_redirect_url = $view->settings->get( 'edit_redirect_url' );
1060 1
1061
				switch ( $edit_redirect ) {
1062 15
1063 1
                    case '0':
1064 1
	                    $redirect_url = $back_link;
1065 1
	                    $entry_updated_message = sprintf( esc_attr_x('Entry Updated. %sReturning to Entry%s', 'Replacements are HTML', 'gravityview'), '<a href="'. esc_url( $redirect_url ) .'">', '</a>' );
1066 1
                        break;
1067
1068 14
                    case '1':
1069
	                    $redirect_url = $directory_link = GravityView_API::directory_link();
1070 14
	                    $entry_updated_message = sprintf( esc_attr_x('Entry Updated. %sReturning to %s%s', 'Replacement 1 is HTML. Replacement 2 is the title of the page where the user will be taken. Replacement 3 is HTML.','gravityview'), '<a href="'. esc_url( $redirect_url ) . '">', esc_html( $view->post_title ), '</a>' );
0 ignored issues
show
Documentation introduced by
The property post_title does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1071 14
	                    break;
1072
1073
                    case '2':
1074 17
	                    $redirect_url = $edit_redirect_url;
1075 3
	                    $redirect_url = GFCommon::replace_variables( $redirect_url, $this->form, $this->entry, false, false, false, 'text' );
1076
	                    $entry_updated_message = sprintf( esc_attr_x('Entry Updated. %sRedirecting to %s%s', 'Replacement 1 is HTML. Replacement 2 is the URL where the user will be taken. Replacement 3 is HTML.','gravityview'), '<a href="'. esc_url( $redirect_url ) . '">', esc_html( $edit_redirect_url ), '</a>' );
1077
                        break;
1078
1079
                    case '':
1080
                    default:
1081
					    $entry_updated_message = sprintf( esc_attr__('Entry Updated. %sReturn to Entry%s', 'gravityview'), '<a href="'. esc_url( $back_link ) .'">', '</a>' );
1082
                        break;
1083
				}
1084
1085
				if ( isset( $redirect_url ) ) {
1086 17
					$entry_updated_message .= sprintf( '<script>window.location.href = %s;</script><noscript><meta http-equiv="refresh" content="0;URL=%s" /></noscript>', json_encode( $redirect_url ), esc_attr( $redirect_url ) );
1087
				}
1088 17
1089
				/**
1090
				 * @filter `gravityview/edit_entry/success` Modify the edit entry success message (including the anchor link)
1091
				 * @since 1.5.4
1092 18
				 * @param string $entry_updated_message Existing message
1093
				 * @param int $view_id View ID
1094
				 * @param array $entry Gravity Forms entry array
1095
				 * @param string $back_link URL to return to the original entry. @since 1.6
1096
				 */
1097
				$message = apply_filters( 'gravityview/edit_entry/success', $entry_updated_message , $this->view_id, $this->entry, $back_link );
1098
1099
				echo GVCommon::generate_notice( $message );
1100
			}
1101 18
1102
		}
1103
	}
1104
1105
	/**
1106
	 * Display the Edit Entry form in the original Gravity Forms format
1107
	 *
1108 18
	 * @since 1.9
1109
	 *
1110 18
	 * @return void
1111 18
	 */
1112 18
	private function render_edit_form() {
1113
1114 18
		/**
1115 18
		 * @action `gravityview/edit-entry/render/before` Before rendering the Edit Entry form
1116
		 * @since 1.17
1117
		 * @param GravityView_Edit_Entry_Render $this
1118 18
		 */
1119
		do_action( 'gravityview/edit-entry/render/before', $this );
1120
1121
		add_filter( 'gform_pre_render', array( $this, 'filter_modify_form_fields'), 5000, 3 );
1122 18
		add_filter( 'gform_submit_button', array( $this, 'render_form_buttons') );
1123
		add_filter( 'gform_next_button', array( $this, 'render_form_buttons' ) );
1124 18
		add_filter( 'gform_previous_button', array( $this, 'render_form_buttons' ) );
1125
		add_filter( 'gform_disable_view_counter', '__return_true' );
1126 18
1127
		add_filter( 'gform_field_input', array( $this, 'verify_user_can_edit_post' ), 5, 5 );
1128 18
		add_filter( 'gform_field_input', array( $this, 'modify_edit_field_input' ), 10, 5 );
1129 18
1130 18
		// We need to remove the fake $_GET['page'] arg to avoid rendering form as if in admin.
1131 18
		unset( $_GET['page'] );
1132 18
1133
		$this->show_next_button = false;
1134 18
		$this->show_previous_button = false;
1135
1136
		// TODO: Verify multiple-page forms
1137
		if ( GFCommon::has_pages( $this->form ) && apply_filters( 'gravityview/features/paged-edit', false ) ) {
1138
			if ( intval( $page_number = \GV\Utils::_POST( 'gform_target_page_number_' . $this->form['id'], 1 ) ) > 1 ) {
1139
				GFFormDisplay::$submission[ $this->form['id'] ][ 'form' ] = $this->form;
1140
				GFFormDisplay::$submission[ $this->form['id'] ][ 'is_valid' ] = true;
1141 18
				GFFormDisplay::$submission[ $this->form['id'] ][ 'page_number' ] = $page_number;
1142 18
			}
1143
1144
			if ( ( $page_number = intval( $page_number ) ) < 2 ) {
1145
				$this->show_next_button = true; // First page
1146
			}
1147
1148
			$last_page = \GFFormDisplay::get_max_page_number( $this->form );
1149 18
1150 18
			$has_more_pages = $page_number < $last_page;
1151
1152
			if ( $has_more_pages ) {
1153
				$this->show_next_button = true; // Not the last page
1154
			} else {
1155
				$this->show_update_button = true; // The last page
1156
			}
1157
1158
			if ( $page_number > 1 ) {
1159
				$this->show_previous_button = true; // Not the first page
1160
			}
1161
		} else {
1162
			$this->show_update_button = true;
1163
		}
1164
1165
		ob_start(); // Prevent PHP warnings possibly caused by prefilling list fields for conditional logic
1166
1167 18
		$html = GFFormDisplay::get_form( $this->form['id'], false, false, true, $this->entry );
1168
1169
		ob_get_clean();
1170 18
1171 17
	    remove_filter( 'gform_pre_render', array( $this, 'filter_modify_form_fields' ), 5000 );
1172
		remove_filter( 'gform_submit_button', array( $this, 'render_form_buttons' ) );
1173 4
		remove_filter( 'gform_next_button', array( $this, 'render_form_buttons' ) );
1174
		remove_filter( 'gform_previous_button', array( $this, 'render_form_buttons' ) );
1175
		remove_filter( 'gform_disable_view_counter', '__return_true' );
1176 18
		remove_filter( 'gform_field_input', array( $this, 'verify_user_can_edit_post' ), 5 );
1177
		remove_filter( 'gform_field_input', array( $this, 'modify_edit_field_input' ), 10 );
1178 18
1179
		echo $html;
1180
1181 18
		/**
1182 18
		 * @action `gravityview/edit-entry/render/after` After rendering the Edit Entry form
1183
		 * @since 1.17
1184
		 * @param GravityView_Edit_Entry_Render $this
1185 18
		 */
1186
		do_action( 'gravityview/edit-entry/render/after', $this );
1187 18
	}
1188
1189
	/**
1190
	 * Display the Update/Cancel/Delete buttons for the Edit Entry form
1191
	 * @since 1.8
1192
	 * @return string
1193
	 */
1194
	public function render_form_buttons() {
1195
		return gravityview_ob_include( GravityView_Edit_Entry::$file .'/partials/form-buttons.php', $this );
0 ignored issues
show
Bug introduced by
The property file cannot be accessed from this context as it is declared private in class GravityView_Edit_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1196
	}
1197
1198
1199
	/**
1200
	 * Modify the form fields that are shown when using GFFormDisplay::get_form()
1201
	 *
1202
	 * By default, all fields will be shown. We only want the Edit Tab configured fields to be shown.
1203 18
	 *
1204
	 * @param array $form
1205 18
	 * @param boolean $ajax Whether in AJAX mode
1206 18
	 * @param array|string $field_values Passed parameters to the form
1207
	 *
1208
	 * @since 1.9
1209 2
	 *
1210
	 * @return array Modified form array
1211
	 */
1212 2
	public function filter_modify_form_fields( $form, $ajax = false, $field_values = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $ajax is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $field_values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1213
1214
		// In case we have validated the form, use it to inject the validation results into the form render
1215
		if( isset( $this->form_after_validation ) && $this->form_after_validation['id'] === $form['id'] ) {
1216
			$form = $this->form_after_validation;
1217
		} else {
1218 1
			$form['fields'] = $this->get_configured_edit_fields( $form, $this->view_id );
1219
		}
1220 1
1221
		$form = $this->filter_conditional_logic( $form );
1222
1223
		$form = $this->prefill_conditional_logic( $form );
1224
1225
		// for now we don't support Save and Continue feature.
1226
		if( ! self::$supports_save_and_continue ) {
1227
	        unset( $form['save'] );
1228 2
		}
1229 1
1230
		$form = $this->unselect_default_values( $form );
1231
1232 2
		return $form;
1233
	}
1234
1235
	/**
1236
	 * 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.
1237
	 *
1238
	 * @since 1.16.2.2
1239
	 *
1240
	 * @param string $field_content Always empty. Returning not-empty overrides the input.
1241
	 * @param GF_Field $field
1242
	 * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1243
	 * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1244
	 * @param int $form_id Form ID
1245
	 *
1246
	 * @return string If error, the error message. If no error, blank string (modify_edit_field_input() runs next)
1247 18
	 */
1248
	public function verify_user_can_edit_post( $field_content = '', $field, $value, $lead_id = 0, $form_id ) {
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $lead_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1249 18
1250
		if( ! GFCommon::is_post_field( $field ) ) {
1251
			return $field_content;
1252
		}
1253
1254 18
        $message = null;
1255 18
1256
        // First, make sure they have the capability to edit the post.
1257 18
        if( false === current_user_can( 'edit_post', $this->entry['post_id'] ) ) {
1258 18
1259
            /**
1260 1
             * @filter `gravityview/edit_entry/unsupported_post_field_text` Modify the message when someone isn't able to edit a post
1261
             * @param string $message The existing "You don't have permission..." text
1262
             */
1263
            $message = apply_filters('gravityview/edit_entry/unsupported_post_field_text', __('You don&rsquo;t have permission to edit this post.', 'gravityview') );
1264 18
1265
        } elseif( null === get_post( $this->entry['post_id'] ) ) {
1266 18
            /**
1267
             * @filter `gravityview/edit_entry/no_post_text` Modify the message when someone is editing an entry attached to a post that no longer exists
1268
             * @param string $message The existing "This field is not editable; the post no longer exists." text
1269 18
             */
1270
            $message = apply_filters('gravityview/edit_entry/no_post_text', __('This field is not editable; the post no longer exists.', 'gravityview' ) );
1271 18
        }
1272
1273
        if( $message ) {
1274 18
            $field_content = sprintf('<div class="ginput_container ginput_container_' . $field->type . '">%s</div>', wpautop( $message ) );
1275 3
        }
1276
1277 18
        return $field_content;
1278
	}
1279
1280
	/**
1281 18
	 *
1282
	 * Fill-in the saved values into the form inputs
1283 18
	 *
1284
	 * @param string $field_content Always empty. Returning not-empty overrides the input.
1285
	 * @param GF_Field $field
1286
	 * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1287 18
	 * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1288
	 * @param int $form_id Form ID
1289
	 *
1290
	 * @return mixed
1291
	 */
1292
	public function modify_edit_field_input( $field_content = '', $field, $value, $lead_id = 0, $form_id ) {
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $lead_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1293
1294
		$gv_field = GravityView_Fields::get_associated_field( $field );
1295
1296
		// If the form has been submitted, then we don't need to pre-fill the values,
1297 18
		// Except for fileupload type and when a field input is overridden- run always!!
1298
		if(
1299
			( $this->is_edit_entry_submission() && !in_array( $field->type, array( 'fileupload', 'post_image' ) ) )
1300
			&& false === ( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) )
1301
			&& ! GFCommon::is_product_field( $field->type )
1302
			|| ! empty( $field_content )
1303
			|| in_array( $field->type, array( 'honeypot' ) )
1304
		) {
1305 18
	        return $field_content;
1306
		}
1307
1308 18
		// SET SOME FIELD DEFAULTS TO PREVENT ISSUES
1309
		$field->adminOnly = false; /** @see GFFormDisplay::get_counter_init_script() need to prevent adminOnly */
1310 3
1311
		$field_value = $this->get_field_value( $field );
1312
1313 3
	    // Prevent any PHP warnings, like undefined index
1314
	    ob_start();
1315 3
1316
	    $return = null;
1317 3
1318
		/** @var GravityView_Field $gv_field */
1319 3
		if( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) ) {
1320 3
			$return = $gv_field->get_field_input( $this->form, $field_value, $this->entry, $field );
1321 3
		} else {
1322
	        $return = $field->get_field_input( $this->form, $field_value, $this->entry );
1323
	    }
1324
1325
	    // If there was output, it's an error
1326 3
	    $warnings = ob_get_clean();
1327
1328 3
	    if( !empty( $warnings ) ) {
1329
		    gravityview()->log->error( '{warning}', array( 'warning' => $warnings, 'data' => $field_value ) );
1330
	    }
1331
1332 18
		return $return;
1333
	}
1334
1335 18
	/**
1336
	 * Modify the value for the current field input
1337
	 *
1338
	 * @param GF_Field $field
1339 18
	 *
1340
	 * @return array|mixed|string
1341
	 */
1342 18
	private function get_field_value( $field ) {
1343
1344
		/**
1345
		 * @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.
1346
		 * @param boolean True: override saved values; False: don't override (default)
1347
		 * @param $field GF_Field object Gravity Forms field object
1348
		 * @since 1.13
1349
		 */
1350
		$override_saved_value = apply_filters( 'gravityview/edit_entry/pre_populate/override', false, $field );
1351
1352
		// We're dealing with multiple inputs (e.g. checkbox) but not time or date (as it doesn't store data in input IDs)
1353 18
		if( isset( $field->inputs ) && is_array( $field->inputs ) && !in_array( $field->type, array( 'time', 'date' ) ) ) {
1354
1355
			$field_value = array();
1356
1357
			// only accept pre-populated values if the field doesn't have any choice selected.
1358
			$allow_pre_populated = $field->allowsPrepopulate;
1359
1360
			foreach ( (array)$field->inputs as $input ) {
1361
1362
				$input_id = strval( $input['id'] );
1363 18
1364
				if ( isset( $this->entry[ $input_id ] ) && ! gv_empty( $this->entry[ $input_id ], false, false ) ) {
1365
				    $field_value[ $input_id ] =  'post_category' === $field->type ? GFCommon::format_post_category( $this->entry[ $input_id ], true ) : $this->entry[ $input_id ];
1366
				    $allow_pre_populated = false;
1367
				}
1368
1369
			}
1370
1371
			$pre_value = $field->get_value_submission( array(), false );
1372
1373 18
			$field_value = ! $allow_pre_populated && ! ( $override_saved_value && !gv_empty( $pre_value, false, false ) ) ? $field_value : $pre_value;
1374
1375 18
		} else {
1376
1377
			$id = intval( $field->id );
1378
1379
			// get pre-populated value if exists
1380
			$pre_value = $field->allowsPrepopulate ? GFFormsModel::get_parameter_value( $field->inputName, array(), $field ) : '';
1381
1382
			// saved field entry value (if empty, fallback to the pre-populated value, if exists)
1383
			// or pre-populated value if not empty and set to override saved value
1384
			$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;
1385
1386
			// in case field is post_category but inputType is select, multi-select or radio, convert value into array of category IDs.
1387
			if ( 'post_category' === $field->type && !gv_empty( $field_value, false, false ) ) {
1388 17
				$categories = array();
1389
				foreach ( explode( ',', $field_value ) as $cat_string ) {
1390 17
				    $categories[] = GFCommon::format_post_category( $cat_string, true );
1391
				}
1392
				$field_value = 'multiselect' === $field->get_input_type() ? $categories : implode( '', $categories );
1393
			}
1394
1395 17
		}
1396
1397
		// if value is empty get the default value if defined
1398
		$field_value = $field->get_value_default_if_empty( $field_value );
1399 17
1400 17
	    /**
1401
	     * @filter `gravityview/edit_entry/field_value` Change the value of an Edit Entry field, if needed
1402
	     * @since 1.11
1403 17
	     * @since 1.20 Added third param
1404
	     * @param mixed $field_value field value used to populate the input
1405
	     * @param object $field Gravity Forms field object ( Class GF_Field )
1406
	     * @param GravityView_Edit_Entry_Render $this Current object
1407
	     */
1408
	    $field_value = apply_filters( 'gravityview/edit_entry/field_value', $field_value, $field, $this );
1409
1410
	    /**
1411
	     * @filter `gravityview/edit_entry/field_value_{field_type}` Change the value of an Edit Entry field for a specific field type
1412 17
	     * @since 1.17
1413
	     * @since 1.20 Added third param
1414
	     * @param mixed $field_value field value used to populate the input
1415 1
	     * @param GF_Field $field Gravity Forms field object
1416
	     * @param GravityView_Edit_Entry_Render $this Current object
1417 1
	     */
1418 1
	    $field_value = apply_filters( 'gravityview/edit_entry/field_value_' . $field->type , $field_value, $field, $this );
1419
1420 1
		return $field_value;
1421
	}
1422
1423 1
1424 1
	// ---- Entry validation
1425
1426
	/**
1427
	 * Add field keys that Gravity Forms expects.
1428 1
	 *
1429 1
	 * @see GFFormDisplay::validate()
1430 1
	 * @param  array $form GF Form
1431
	 * @return array       Modified GF Form
1432
	 */
1433
	public function gform_pre_validation( $form ) {
1434
1435
		if( ! $this->verify_nonce() ) {
1436 1
			return $form;
1437
		}
1438
1439
		// Fix PHP warning regarding undefined index.
1440 1
		foreach ( $form['fields'] as &$field) {
1441
1442
			// This is because we're doing admin form pretending to be front-end, so Gravity Forms
1443
			// expects certain field array items to be set.
1444 1
			foreach ( array( 'noDuplicates', 'adminOnly', 'inputType', 'isRequired', 'enablePrice', 'inputs', 'allowedExtensions' ) as $key ) {
1445
	            $field->{$key} = isset( $field->{$key} ) ? $field->{$key} : NULL;
1446
			}
1447 1
1448
			switch( RGFormsModel::get_input_type( $field ) ) {
1449
1450
				/**
1451
				 * 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.
1452
				 *
1453
				 * 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.
1454 1
				 *
1455
				 * @hack
1456
				 */
1457
				case 'fileupload':
1458 1
1459 1
				    // Set the previous value
1460
				    $entry = $this->get_entry();
1461 1
1462
				    $input_name = 'input_'.$field->id;
1463 17
				    $form_id = $form['id'];
1464
1465 12
				    $value = NULL;
1466 7
1467
				    // Use the previous entry value as the default.
1468 12
				    if( isset( $entry[ $field->id ] ) ) {
1469
				        $value = $entry[ $field->id ];
1470
				    }
1471
1472
				    // If this is a single upload file
1473 17
				    if( !empty( $_FILES[ $input_name ] ) && !empty( $_FILES[ $input_name ]['name'] ) ) {
1474
				        $file_path = GFFormsModel::get_file_upload_path( $form['id'], $_FILES[ $input_name ]['name'] );
1475
				        $value = $file_path['url'];
1476
1477
				    } else {
1478
1479
				        // Fix PHP warning on line 1498 of form_display.php for post_image fields
1480
				        // Fix PHP Notice:  Undefined index:  size in form_display.php on line 1511
1481
				        $_FILES[ $input_name ] = array('name' => '', 'size' => '' );
1482
1483
				    }
1484 18
1485
				    if ( \GV\Utils::get( $field, "multipleFiles" ) ) {
1486
1487
				        // If there are fresh uploads, process and merge them.
1488
				        // Otherwise, use the passed values, which should be json-encoded array of URLs
1489
				        if( isset( GFFormsModel::$uploaded_files[$form_id][$input_name] ) ) {
1490
				            $value = empty( $value ) ? '[]' : $value;
1491 18
				            $value = stripslashes_deep( $value );
1492 18
				            $value = GFFormsModel::prepare_value( $form, $field, $value, $input_name, $entry['id'], array());
1493
				        }
1494
1495
				    } else {
1496
1497
				        // A file already exists when editing an entry
1498
				        // We set this to solve issue when file upload fields are required.
1499
				        GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] = $value;
1500
1501
				    }
1502
1503 18
				    $this->entry[ $input_name ] = $value;
1504
				    $_POST[ $input_name ] = $value;
1505
1506 18
				    break;
1507 18
1508
				case 'number':
1509
				    // Fix "undefined index" issue at line 1286 in form_display.php
1510
				    if( !isset( $_POST['input_'.$field->id ] ) ) {
1511 18
				        $_POST['input_'.$field->id ] = NULL;
1512
				    }
1513
				    break;
1514 18
			}
1515
1516 18
		}
1517
1518 18
		return $form;
1519 18
	}
1520
1521
1522
	/**
1523
	 * Process validation for a edit entry submission
1524
	 *
1525
	 * Sets the `is_valid` object var
1526
	 *
1527
	 * @return void
1528
	 */
1529
	private function validate() {
1530
1531
		/**
1532
		 * If using GF User Registration Add-on, remove the validation step, otherwise generates error when updating the entry
1533 18
		 * GF User Registration Add-on version > 3.x has a different class name
1534
		 * @since 1.16.2
1535 18
		 */
1536
		if ( class_exists( 'GF_User_Registration' ) ) {
1537 18
			remove_filter( 'gform_validation', array( GF_User_Registration::get_instance(), 'validate' ) );
1538
		} else  if ( class_exists( 'GFUser' ) ) {
1539 18
			remove_filter( 'gform_validation', array( 'GFUser', 'user_registration_validation' ) );
1540
		}
1541 18
1542
1543 18
		/**
1544 18
		 * For some crazy reason, Gravity Forms doesn't validate Edit Entry form submissions.
1545
		 * You can enter whatever you want!
1546
		 * We try validating, and customize the results using `self::custom_validation()`
1547 18
		 */
1548
		add_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10, 4);
1549
1550 18
		// Needed by the validate funtion
1551 18
		$failed_validation_page = NULL;
1552
		$field_values = RGForms::post( 'gform_field_values' );
1553
1554 2
		// Prevent entry limit from running when editing an entry, also
1555
		// prevent form scheduling from preventing editing
1556
		unset( $this->form['limitEntries'], $this->form['scheduleForm'] );
1557
1558
		// Hide fields depending on Edit Entry settings
1559
		$this->form['fields'] = $this->get_configured_edit_fields( $this->form, $this->view_id );
1560 2
1561
		$this->is_valid = GFFormDisplay::validate( $this->form, $field_values, 1, $failed_validation_page );
1562
1563
		remove_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10 );
1564
	}
1565
1566
1567
	/**
1568
	 * Make validation work for Edit Entry
1569
	 *
1570
	 * Because we're calling the GFFormDisplay::validate() in an unusual way (as a front-end
1571
	 * form pretending to be a back-end form), validate() doesn't know we _can't_ edit post
1572
	 * fields. This goes through all the fields and if they're an invalid post field, we
1573
	 * set them as valid. If there are still issues, we'll return false.
1574
	 *
1575
	 * @param  [type] $validation_results [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1576
	 * @return [type]                     [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1577
	 */
1578
	public function custom_validation( $validation_results ) {
1579
1580
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results: ', array( 'data' => $validation_results ) );
1581
1582
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] $_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
1583
1584
		$gv_valid = true;
1585
1586
		foreach ( $validation_results['form']['fields'] as $key => &$field ) {
1587
1588
			$value = RGFormsModel::get_field_value( $field );
1589 2
			$field_type = RGFormsModel::get_input_type( $field );
1590
1591
			// Validate always
1592
			switch ( $field_type ) {
1593
1594 18
1595
				case 'fileupload' :
1596 1
				case 'post_image':
1597
1598 1
				    // in case nothing is uploaded but there are already files saved
1599
				    if( !empty( $field->failed_validation ) && !empty( $field->isRequired ) && !empty( $value ) ) {
1600
				        $field->failed_validation = false;
1601 1
				        unset( $field->validation_message );
1602
				    }
1603
1604 1
				    // validate if multi file upload reached max number of files [maxFiles] => 2
1605
				    if( \GV\Utils::get( $field, 'maxFiles') && \GV\Utils::get( $field, 'multipleFiles') ) {
1606
1607
				        $input_name = 'input_' . $field->id;
1608
				        //uploaded
1609
				        $file_names = isset( GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] : array();
1610
1611
				        //existent
1612 1
				        $entry = $this->get_entry();
1613
				        $value = NULL;
1614
				        if( isset( $entry[ $field->id ] ) ) {
1615
				            $value = json_decode( $entry[ $field->id ], true );
1616
				        }
1617
1618 1
				        // count uploaded files and existent entry files
1619
				        $count_files = ( is_array( $file_names ) ? count( $file_names ) : 0 ) +
1620
						               ( is_array( $value ) ? count( $value ) : 0 );
1621
1622
				        if( $count_files > $field->maxFiles ) {
1623
				            $field->validation_message = __( 'Maximum number of files reached', 'gravityview' );
1624
				            $field->failed_validation = 1;
1625
				            $gv_valid = false;
1626
1627
				            // in case of error make sure the newest upload files are removed from the upload input
1628
				            GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ] = null;
1629
				        }
1630
1631
				    }
1632
1633
1634
				    break;
1635
1636
			}
1637 1
1638
			// This field has failed validation.
1639
			if( !empty( $field->failed_validation ) ) {
1640
1641
				gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field is invalid.', array( 'data' => array( 'field' => $field, 'value' => $value ) ) );
1642
1643 1
				switch ( $field_type ) {
1644
1645
				    // Captchas don't need to be re-entered.
1646
				    case 'captcha':
1647
1648
				        // Post Image fields aren't editable, so we un-fail them.
1649 18
				    case 'post_image':
1650
				        $field->failed_validation = false;
1651 18
				        unset( $field->validation_message );
1652
				        break;
1653
1654 18
				}
1655
1656 18
				// You can't continue inside a switch, so we do it after.
1657
				if( empty( $field->failed_validation ) ) {
1658
				    continue;
1659
				}
1660
1661
				// checks if the No Duplicates option is not validating entry against itself, since
1662
				// we're editing a stored entry, it would also assume it's a duplicate.
1663
				if( !empty( $field->noDuplicates ) ) {
1664
1665 2
				    $entry = $this->get_entry();
1666
1667 2
				    // If the value of the entry is the same as the stored value
1668
				    // Then we can assume it's not a duplicate, it's the same.
1669 1
				    if( !empty( $entry ) && $value == $entry[ $field->id ] ) {
1670
				        //if value submitted was not changed, then don't validate
1671
				        $field->failed_validation = false;
1672 2
1673
				        unset( $field->validation_message );
1674
1675
				        gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field not a duplicate; it is the same entry.', array( 'data' => $entry ) );
1676
1677
				        continue;
1678
				    }
1679
				}
1680
1681
				// if here then probably we are facing the validation 'At least one field must be filled out'
1682
				if( GFFormDisplay::is_empty( $field, $this->form_id  ) && empty( $field->isRequired ) ) {
1683
				    unset( $field->validation_message );
1684
	                $field->validation_message = false;
1685
				    continue;
1686
				}
1687
1688 19
				$gv_valid = false;
1689
1690
			}
1691 19
1692 19
		}
1693 19
1694
		$validation_results['is_valid'] = $gv_valid;
1695
1696
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results.', array( 'data' => $validation_results ) );
1697
1698
		// We'll need this result when rendering the form ( on GFFormDisplay::get_form )
1699 19
		$this->form_after_validation = $validation_results['form'];
1700
1701
		return $validation_results;
1702 19
	}
1703
1704
1705 19
	/**
1706
	 * TODO: This seems to be hacky... we should remove it. Entry is set when updating the form using setup_vars()!
1707
	 * Get the current entry and set it if it's not yet set.
1708
	 * @return array Gravity Forms entry array
1709
	 */
1710
	public function get_entry() {
1711
1712
		if( empty( $this->entry ) ) {
1713
			// Get the database value of the entry that's being edited
1714
			$this->entry = gravityview_get_entry( GravityView_frontend::is_single_entry() );
1715 19
		}
1716
1717 19
		return $this->entry;
1718
	}
1719
1720
1721
1722
	// --- Filters
1723
1724
	/**
1725
	 * Get the Edit Entry fields as configured in the View
1726
	 *
1727
	 * @since 1.8
1728
	 *
1729
	 * @param int $view_id
1730
	 *
1731
	 * @return array Array of fields that are configured in the Edit tab in the Admin
1732
	 */
1733 18
	private function get_configured_edit_fields( $form, $view_id ) {
1734
1735 18
		// Get all fields for form
1736
		if ( \GV\View::exists( $view_id ) ) {
1737
			$view = \GV\View::by_id( $view_id );
1738
			$properties = $view->fields ? $view->fields->as_configuration() : array();
1739 18
		} else {
1740
			$properties = null;
1741 18
		}
1742
1743
		// If edit tab not yet configured, show all fields
1744 18
		$edit_fields = !empty( $properties['edit_edit-fields'] ) ? $properties['edit_edit-fields'] : NULL;
1745
1746
		// Hide fields depending on admin settings
1747
		$fields = $this->filter_fields( $form['fields'], $edit_fields );
1748 18
1749 5
	    // If Edit Entry fields are configured, remove adminOnly field settings. Otherwise, don't.
1750
	    $fields = $this->filter_admin_only_fields( $fields, $edit_fields, $form, $view_id );
1751
1752
		/**
1753 18
		 * @filter `gravityview/edit_entry/form_fields` Modify the fields displayed in Edit Entry form
1754 3
		 * @since 1.17
1755
		 * @param GF_Field[] $fields Gravity Forms form fields
1756
		 * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1757
		 * @param array $form GF Form array (`fields` key modified to have only fields configured to show in Edit Entry)
1758
		 * @param int $view_id View ID
1759
		 */
1760 18
		$fields = apply_filters( 'gravityview/edit_entry/form_fields', $fields, $edit_fields, $form, $view_id );
1761 15
1762 15
		return $fields;
1763 15
	}
1764 3
1765
1766
	/**
1767 15
	 * Filter area fields based on specified conditions
1768 2
	 *  - This filter removes the fields that have calculation configured
1769
	 *  - Hides fields that are hidden, etc.
1770
	 *
1771 13
	 * @uses GravityView_Edit_Entry::user_can_edit_field() Check caps
1772
	 * @access private
1773
	 * @param GF_Field[] $fields
1774 15
	 * @param array $configured_fields
1775
	 * @since  1.5
1776
	 * @return array $fields
1777
	 */
1778 5
	private function filter_fields( $fields, $configured_fields ) {
1779
1780
		if( empty( $fields ) || !is_array( $fields ) ) {
1781 5
			return $fields;
1782 5
		}
1783 5
1784 5
		$edit_fields = array();
1785
1786
		$field_type_blacklist = $this->loader->get_field_blacklist( $this->entry );
1787
1788
		if ( empty( $configured_fields ) && apply_filters( 'gravityview/features/paged-edit', false ) ) {
1789
			$field_type_blacklist = array_diff( $field_type_blacklist, array( 'page' ) );
1790
		}
1791 5
1792
		// First, remove blacklist or calculation fields
1793
		foreach ( $fields as $key => $field ) {
1794
1795
			// Remove the fields that have calculation properties and keep them to be used later
1796
			// @since 1.16.2
1797
			if( $field->has_calculation() ) {
1798
				$this->fields_with_calculation[] = $field;
1799
				// don't remove the calculation fields on form render.
1800
			}
1801
1802 5
			if( in_array( $field->type, $field_type_blacklist ) ) {
1803
				unset( $fields[ $key ] );
1804 5
			}
1805
		}
1806 5
1807
		// The Edit tab has not been configured, so we return all fields by default.
1808 5
		// But we do keep the hidden ones hidden please, for everyone :)
1809
		if ( empty( $configured_fields ) ) {
1810
			$out_fields = array();
1811
			foreach ( $fields as &$field ) {
1812 5
				if ( 'hidden' === $field->type ) {
1813
					continue; // A hidden field is just hidden
1814
				}
1815
1816
				if ( 'hidden' == $field->visibility ) {
1817
					continue; // Same
1818
				}
1819
1820 5
				$out_fields[] = $field;
1821
			}
1822 5
1823
			return array_values( $out_fields );
1824
		}
1825
1826
		// The edit tab has been configured, so we loop through to configured settings
1827
		foreach ( $configured_fields as $configured_field ) {
1828
1829
	        /** @var GF_Field $field */
1830
	        foreach ( $fields as $field ) {
1831
				if( intval( $configured_field['id'] ) === intval( $field->id ) && $this->user_can_edit_field( $configured_field, false ) ) {
1832
				    $edit_fields[] = $this->merge_field_properties( $field, $configured_field );
1833
				    break;
1834
				}
1835
1836
			}
1837
1838 18
		}
1839
1840
		return $edit_fields;
1841
1842
	}
1843
1844
	/**
1845
	 * Override GF Form field properties with the ones defined on the View
1846
	 * @param  GF_Field $field GF Form field object
1847
	 * @param  array $field_setting  GV field options
1848
	 * @since  1.5
1849 18
	 * @return array|GF_Field
1850
	 */
1851 18
	private function merge_field_properties( $field, $field_setting ) {
1852 1
1853
		$return_field = $field;
1854
1855
		if( empty( $field_setting['show_label'] ) ) {
1856
			$return_field->label = '';
1857 1
		} elseif ( !empty( $field_setting['custom_label'] ) ) {
1858
			$return_field->label = $field_setting['custom_label'];
1859
		}
1860 18
1861 18
		if( !empty( $field_setting['custom_class'] ) ) {
1862
			$return_field->cssClass .= ' '. gravityview_sanitize_html_class( $field_setting['custom_class'] );
1863
		}
1864 18
1865
		/**
1866
		 * Normalize page numbers - avoid conflicts with page validation
1867
		 * @since 1.6
1868
		 */
1869
		$return_field->pageNumber = 1;
1870
1871
		return $return_field;
1872
1873
	}
1874
1875
	/**
1876
	 * Remove fields that shouldn't be visible based on the Gravity Forms adminOnly field property
1877
	 *
1878
	 * @since 1.9.1
1879 18
	 *
1880
	 * @param array|GF_Field[] $fields Gravity Forms form fields
1881 18
	 * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1882
	 * @param array $form GF Form array
1883 18
	 * @param int $view_id View ID
1884 18
	 *
1885
	 * @return array Possibly modified form array
1886
	 */
1887 2
	private function filter_admin_only_fields( $fields = array(), $edit_fields = null, $form = array(), $view_id = 0 ) {
1888 2
1889 1
	    /**
1890
		 * @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
1891
	     * If the Edit Entry tab is not configured, adminOnly fields will not be shown to non-administrators.
1892
	     * If the Edit Entry tab *is* configured, adminOnly fields will be shown to non-administrators, using the configured GV permissions
1893
	     * @since 1.9.1
1894 18
	     * @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.
1895
	     * @param array $form GF Form array
1896
	     * @param int $view_id View ID
1897
	     */
1898
	    $use_gf_adminonly_setting = apply_filters( 'gravityview/edit_entry/use_gf_admin_only_setting', empty( $edit_fields ), $form, $view_id );
1899
1900
	    if( $use_gf_adminonly_setting && false === GVCommon::has_cap( 'gravityforms_edit_entries', $this->entry['id'] ) ) {
1901
			foreach( $fields as $k => $field ) {
1902
				if( $field->adminOnly ) {
1903
				    unset( $fields[ $k ] );
1904
				}
1905
			}
1906
			return array_values( $fields );
1907
		}
1908
1909
	    foreach( $fields as &$field ) {
1910
		    $field->adminOnly = false;
1911
		}
1912 18
1913
		return $fields;
1914 18
	}
1915 16
1916
	/**
1917
	 * Checkboxes and other checkbox-based controls should not
1918
	 * display default checks in edit mode.
1919
	 *
1920 2
	 * https://github.com/gravityview/GravityView/1149
1921
	 *
1922 2
	 * @since 2.1
1923
	 *
1924
	 * @param array $form Gravity Forms array object
1925
	 *
1926
	 * @return array $form, modified to default checkboxes, radios from showing up.
1927
	 */
1928
	private function unselect_default_values( $form ) {
1929
1930
	    foreach ( $form['fields'] as &$field ) {
1931
1932
			if ( empty( $field->choices ) ) {
1933
                continue;
1934
			}
1935 2
1936
            foreach ( $field->choices as &$choice ) {
1937 2
				if ( \GV\Utils::get( $choice, 'isSelected' ) ) {
1938
					$choice['isSelected'] = false;
1939 2
				}
1940
			}
1941
		}
1942
1943
		return $form;
1944
	}
1945
1946
	// --- Conditional Logic
1947
1948
	/**
1949
	 * Conditional logic isn't designed to work with forms that already have content. When switching input values,
1950
	 * the dependent fields will be blank.
1951 2
	 *
1952
	 * Note: This is because GF populates a JavaScript variable with the input values. This is tough to filter at the input level;
1953
	 * via the `gform_field_value` filter; it requires lots of legwork. Doing it at the form level is easier.
1954
	 *
1955
	 * @since 1.17.4
1956
	 *
1957
	 * @param array $form Gravity Forms array object
1958 2
	 *
1959
	 * @return array $form, modified to fix conditional
1960
	 */
1961
	function prefill_conditional_logic( $form ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1962
1963
		if( ! GFFormDisplay::has_conditional_logic( $form ) ) {
1964
			return $form;
1965
		}
1966
1967
		// Have Conditional Logic pre-fill fields as if the data were default values
1968
		/** @var GF_Field $field */
1969
		foreach ( $form['fields'] as &$field ) {
1970 18
1971
			if( 'checkbox' === $field->type ) {
1972
				foreach ( $field->get_entry_inputs() as $key => $input ) {
1973
				    $input_id = $input['id'];
1974
				    $choice = $field->choices[ $key ];
1975
				    $value = \GV\Utils::get( $this->entry, $input_id );
1976
				    $match = RGFormsModel::choice_value_match( $field, $choice, $value );
1977
				    if( $match ) {
1978 18
				        $field->choices[ $key ]['isSelected'] = true;
1979 18
				    }
1980 18
				}
1981 18
			} else {
1982
1983 18
				// We need to run through each field to set the default values
1984 18
				foreach ( $this->entry as $field_id => $field_value ) {
1985 18
1986 3
				    if( floatval( $field_id ) === floatval( $field->id ) ) {
1987 3
1988
				        if( 'list' === $field->type ) {
1989
				            $list_rows = maybe_unserialize( $field_value );
1990
1991
				            $list_field_value = array();
1992 2
				            foreach ( (array) $list_rows as $row ) {
1993 2
				                foreach ( (array) $row as $column ) {
1994
				                    $list_field_value[] = $column;
1995
				                }
1996
				            }
1997
1998
				            $field->defaultValue = serialize( $list_field_value );
1999
				        } else {
2000 2
				            $field->defaultValue = $field_value;
2001
				        }
2002 2
				    }
2003 2
				}
2004
			}
2005
		}
2006
2007
		return $form;
2008
	}
2009
2010 18
	/**
2011 2
	 * Remove the conditional logic rules from the form button and the form fields, if needed.
2012 2
	 *
2013
	 * @todo Merge with caller method
2014 2
	 * @since 1.9
2015
	 *
2016 2
	 * @param array $form Gravity Forms form
2017 1
	 * @return array Modified form, if not using Conditional Logic
2018 1
	 */
2019
	private function filter_conditional_logic( $form ) {
2020
		/**
2021
		 * Fields that are tied to a conditional logic field that is not present in the view
2022
		 * have to still be displayed, if the condition is met.
2023
		 *
2024
		 * @see https://github.com/gravityview/GravityView/issues/840
2025 18
		 * @since develop
2026
		 */
2027
		$the_form = GFAPI::get_form( $form['id'] );
2028
		$editable_ids = array();
2029
		foreach ( $form['fields'] as $field ) {
2030
			$editable_ids[] = $field['id']; // wp_list_pluck is destructive in this context
2031
		}
2032
		$remove_conditions_rule = array();
2033 18
		foreach ( $the_form['fields'] as $field ) {
2034
			if ( ! empty( $field->conditionalLogic ) && ! empty( $field->conditionalLogic['rules'] ) ) {
2035 18
				foreach ( $field->conditionalLogic['rules'] as $i => $rule ) {
2036 18
					if ( ! in_array( $rule['fieldId'], $editable_ids ) ) {
2037
						/**
2038
						 * This conditional field is not editable in this View.
2039
						 * We need to remove the rule, but only if it matches.
2040
						 */
2041
						if ( $_field = GFAPI::get_field( $the_form, $rule['fieldId'] ) ) {
2042
							$value = $_field->get_value_export( $this->entry );
2043
						} elseif ( isset( $this->entry[ $rule['fieldId'] ] ) ) {
2044
							$value = $this->entry[ $rule['fieldId'] ];
2045
						} else {
2046
							$value = gform_get_meta( $this->entry['id'], $rule['fieldId'] );
2047
						}
2048
2049
						$match = GFFormsModel::matches_operation( $value, $rule['value'], $rule['operator'] );
2050
						
2051
						if ( $match ) {
2052
							$remove_conditions_rule[] = array( $field['id'], $i );
2053
						}
2054
					}
2055
				}
2056
			}
2057
		}
2058
2059 18
		if ( $remove_conditions_rule ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $remove_conditions_rule of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2060
			foreach ( $form['fields'] as &$field ) {
2061 18
				foreach ( $remove_conditions_rule as $_remove_conditions_r ) {
2062
2063
				    list( $rule_field_id, $rule_i ) = $_remove_conditions_r;
2064
2065
					if ( $field['id'] == $rule_field_id ) {
2066 18
						unset( $field->conditionalLogic['rules'][ $rule_i ] );
2067
						gravityview()->log->debug( 'Removed conditional rule #{rule} for field {field_id}', array( 'rule' => $rule_i, 'field_id' => $field['id'] ) );
2068
					}
2069
				}
2070
			}
2071
		}
2072
2073
		/** Normalize the indices... */
2074
		$form['fields'] = array_values( $form['fields'] );
2075
2076
		/**
2077
		 * @filter `gravityview/edit_entry/conditional_logic` Should the Edit Entry form use Gravity Forms conditional logic showing/hiding of fields?
2078
		 * @since 1.9
2079
		 * @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
2080
		 * @param array $form Gravity Forms form
2081
		 */
2082
		$use_conditional_logic = apply_filters( 'gravityview/edit_entry/conditional_logic', true, $form );
2083
2084 19
		if( $use_conditional_logic ) {
2085
			return $form;
2086 19
		}
2087
2088
		foreach( $form['fields'] as &$field ) {
2089
			/* @var GF_Field $field */
2090
			$field->conditionalLogic = null;
2091
		}
2092
2093 19
		unset( $form['button']['conditionalLogic'] );
2094
2095
		return $form;
2096
2097
	}
2098
2099 19
	/**
2100
	 * Disable the Gravity Forms conditional logic script and features on the Edit Entry screen
2101
	 *
2102
	 * @since 1.9
2103 19
	 *
2104
	 * @param $has_conditional_logic
2105
	 * @param $form
2106
	 * @return mixed
2107
	 */
2108
	public function manage_conditional_logic( $has_conditional_logic, $form ) {
2109
2110
		if( ! $this->is_edit_entry() ) {
2111
			return $has_conditional_logic;
2112
		}
2113
2114
	    /** @see GravityView_Edit_Entry_Render::filter_conditional_logic for filter documentation */
2115
		return apply_filters( 'gravityview/edit_entry/conditional_logic', $has_conditional_logic, $form );
2116
	}
2117 19
2118 1
2119
	// --- User checks and nonces
2120
2121 19
	/**
2122
	 * Check if the user can edit the entry
2123
	 *
2124
	 * - Is the nonce valid?
2125
	 * - Does the user have the right caps for the entry
2126 19
	 * - Is the entry in the trash?
2127 19
	 *
2128
	 * @todo Move to GVCommon
2129
	 *
2130 1
	 * @param  boolean $echo Show error messages in the form?
2131
	 * @return boolean        True: can edit form. False: nope.
2132 1
	 */
2133
	private function user_can_edit_entry( $echo = false ) {
2134
2135
		$error = NULL;
2136
2137 1
		/**
2138 1
		 *  1. Permalinks are turned off
2139
		 *  2. There are two entries embedded using oEmbed
2140
		 *  3. One of the entries has just been saved
2141 1
		 */
2142
		if( !empty( $_POST['lid'] ) && !empty( $_GET['entry'] ) && ( $_POST['lid'] !== $_GET['entry'] ) ) {
2143
2144 1
			$error = true;
2145
2146 1
		}
2147
2148
		if( !empty( $_GET['entry'] ) && (string)$this->entry['id'] !== $_GET['entry'] ) {
2149
2150
			$error = true;
2151
2152
		} elseif( ! $this->verify_nonce() ) {
2153
2154
			/**
2155
			 * If the Entry is embedded, there may be two entries on the same page.
2156
			 * If that's the case, and one is being edited, the other should fail gracefully and not display an error.
2157 5
			 */
2158
			if( GravityView_oEmbed::getInstance()->get_entry_id() ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \GravityView_oEmbed::get...tance()->get_entry_id() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Deprecated Code introduced by
The method GravityView_oEmbed::getInstance() has been deprecated with message: Use \GV\oEmbed instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Deprecated Code introduced by
The method GravityView_oEmbed::get_entry_id() has been deprecated with message: Use \GV\oEmbed instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2159 5
				$error = true;
2160
			} else {
2161 5
				$error = __( 'The link to edit this entry is not valid; it may have expired.', 'gravityview');
2162 1
			}
2163
2164
		}
2165
2166 5
		if( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $this->entry ) ) {
2167 5
			$error = __( 'You do not have permission to edit this entry.', 'gravityview');
2168
		}
2169
2170 1
		if( $this->entry['status'] === 'trash' ) {
2171
			$error = __('You cannot edit the entry; it is in the trash.', 'gravityview' );
2172
		}
2173
2174 1
		// No errors; everything's fine here!
2175
		if( empty( $error ) ) {
2176 1
			return true;
2177
		}
2178
2179
		if( $echo && $error !== true ) {
2180
2181
	        $error = esc_html( $error );
2182
2183
	        /**
2184
	         * @since 1.9
2185
	         */
2186
	        if ( ! empty( $this->entry ) ) {
2187
		        $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;" ) );
2188
	        }
2189 5
2190
			echo GVCommon::generate_notice( wpautop( $error ), 'gv-error error');
2191
		}
2192 5
2193 4
		gravityview()->log->error( '{error}', array( 'error' => $error ) );
2194
2195
		return false;
2196 1
	}
2197
2198 1
2199 1
	/**
2200
	 * Check whether a field is editable by the current user, and optionally display an error message
2201
	 * @uses  GravityView_Edit_Entry->check_user_cap_edit_field() Check user capabilities
2202
	 * @param  array  $field Field or field settings array
2203
	 * @param  boolean $echo  Whether to show error message telling user they aren't allowed
2204
	 * @return boolean         True: user can edit the current field; False: nope, they can't.
2205
	 */
2206
	private function user_can_edit_field( $field, $echo = false ) {
2207
2208
		$error = NULL;
2209
2210 18
		if( ! $this->check_user_cap_edit_field( $field ) ) {
2211
			$error = __( 'You do not have permission to edit this field.', 'gravityview');
2212
		}
2213 18
2214
		// No errors; everything's fine here!
2215
		if( empty( $error ) ) {
2216
			return true;
2217
		}
2218 18
2219
		if( $echo ) {
2220
			echo GVCommon::generate_notice( wpautop( esc_html( $error ) ), 'gv-error error');
2221
		}
2222
2223 18
		gravityview()->log->error( '{error}', array( 'error' => $error ) );
2224
2225
		return false;
2226
2227
	}
2228
2229
2230
	/**
2231
	 * checks if user has permissions to edit a specific field
2232 18
	 *
2233
	 * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_field for maximum security!!
2234 18
	 *
2235
	 * @param  [type] $field [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2236
	 * @return bool
2237
	 */
2238
	private function check_user_cap_edit_field( $field ) {
2239
2240
		// If they can edit any entries (as defined in Gravity Forms), we're good.
2241
		if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ) ) ) {
2242
			return true;
2243
		}
2244
2245
		$field_cap = isset( $field['allow_edit_cap'] ) ? $field['allow_edit_cap'] : false;
2246
2247
		if( $field_cap ) {
2248
			return GVCommon::has_cap( $field['allow_edit_cap'] );
2249
		}
2250
2251
		return false;
2252
	}
2253
2254
2255
	/**
2256
	 * Is the current nonce valid for editing the entry?
2257
	 * @return boolean
2258
	 */
2259
	public function verify_nonce() {
2260
2261
		// Verify form submitted for editing single
2262
		if( $this->is_edit_entry_submission() ) {
2263
			$valid = wp_verify_nonce( $_POST[ self::$nonce_field ], self::$nonce_field );
2264
		}
2265
2266
		// Verify
2267
		else if( ! $this->is_edit_entry() ) {
2268
			$valid = false;
2269
		}
2270
2271
		else {
2272
			$valid = wp_verify_nonce( $_GET['edit'], self::$nonce_key );
2273
		}
2274
2275
		/**
2276
		 * @filter `gravityview/edit_entry/verify_nonce` Override Edit Entry nonce validation. Return true to declare nonce valid.
2277
		 * @since 1.13
2278
		 * @param int|boolean $valid False if invalid; 1 or 2 when nonce was generated
2279
		 * @param string $nonce_field Key used when validating submissions. Default: is_gv_edit_entry
2280
		 */
2281
		$valid = apply_filters( 'gravityview/edit_entry/verify_nonce', $valid, self::$nonce_field );
2282
2283
		return $valid;
2284
	}
2285
2286
2287
	/**
2288
	 * Multiselect in GF 2.2 became a json_encoded value. Fix it.
2289
	 *
2290
	 * As a hack for now we'll implode it back.
2291
	 */
2292
	public function fix_multiselect_value_serialization( $field_value, $field, $_this ) {
0 ignored issues
show
Unused Code introduced by
The parameter $_this is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2293
		if ( empty ( $field->storageType ) || $field->storageType != 'json' ) {
2294
			return $field_value;
2295
		}
2296
2297
		$maybe_json = @json_decode( $field_value, true );
2298
2299
		if ( $maybe_json ) {
2300
			return implode( ',', $maybe_json );
2301
		}
2302
2303
		return $field_value;
2304
	}
2305
2306
2307
2308
} //end class
2309