Completed
Push — develop ( d04c10...8cb174 )
by Gennady
20:01
created

GravityView_Edit_Entry_Render::render_edit_form()   C

Complexity

Conditions 9
Paths 33

Size

Total Lines 101

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 11.2376

Importance

Changes 0
Metric Value
cc 9
nc 33
nop 0
dl 0
loc 101
ccs 30
cts 43
cp 0.6977
crap 11.2376
rs 6.4444
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
	/**
120
	 * Internal page button states.
121
	 *
122
	 * @var bool
123
	 *
124
	 * @since develop
125
	 */
126
	public $show_previous_button;
127
	public $show_next_button;
128
	public $show_update_button;
129
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 18
		$this->loader = $loader;
132 18
	}
133
134 18
	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
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 18
		add_action( 'wp_footer', array( $this, 'prevent_render_form' ) );
142
143
		// Stop Gravity Forms processing what is ours!
144 18
		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 18
		add_action( 'gravityview_edit_entry', array( $this, 'init' ), 10, 4 );
149
150
		// Disable conditional logic if needed (since 1.9)
151 18
		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 18
		add_filter( 'gform_plupload_settings', array( $this, 'modify_fileupload_settings' ), 10, 3 );
155
156
		// Add fields expected by GFFormDisplay::validate()
157 18
		add_filter( 'gform_pre_validation', array( $this, 'gform_pre_validation') );
158
159
		// Fix multiselect value for GF 2.2
160 18
		add_filter( 'gravityview/edit_entry/field_value_multiselect', array( $this, 'fix_multiselect_value_serialization' ), 10, 3 );
161 18
	}
162
163
	/**
164
	 * Don't show any forms embedded on a page when GravityView is in Edit Entry mode
165
	 *
166
	 * Adds a `__return_empty_string` filter on the Gravity Forms shortcode on the `wp_head` action
167
	 * And then removes it on the `wp_footer` action
168
	 *
169
	 * @since 1.16.1
170
	 *
171
	 * @return void
172
	 */
173 1
	public function prevent_render_form() {
174 1
		if( $this->is_edit_entry() ) {
175 1
			if( 'wp_head' === current_filter() ) {
176 1
				add_filter( 'gform_shortcode_form', '__return_empty_string' );
177
			} else {
178 1
				remove_filter( 'gform_shortcode_form', '__return_empty_string' );
179
			}
180
		}
181 1
	}
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 1
	public function prevent_maybe_process_form() {
189
190 1
	    if( ! $this->is_edit_entry_submission() ) {
191 1
			return;
192
		}
193
194
		gravityview()->log->debug( 'GravityView_Edit_Entry[prevent_maybe_process_form] Removing GFForms::maybe_process_form() action.' );
195
196
		remove_action( 'wp',  array( 'RGForms', 'maybe_process_form'), 9 );
197
		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 23
	public function is_edit_entry() {
205
206 23
		$is_edit_entry = GravityView_frontend::is_single_entry() && ! empty( $_GET['edit'] );
207
208 23
		return ( $is_edit_entry || $this->is_edit_entry_submission() );
209
	}
210
211
	/**
212
	 * Is the current page an Edit Entry page?
213
	 * @since 1.9
214
	 * @return boolean
215
	 */
216 23
	public function is_edit_entry_submission() {
217 23
		return !empty( $_POST[ self::$nonce_field ] );
218
	}
219
220
	/**
221
	 * When Edit entry view is requested setup the vars
222
	 */
223 18
	private function setup_vars() {
224 18
        global $post;
225
226 18
		$gravityview_view = GravityView_View::getInstance();
227
228
229 18
		$entries = $gravityview_view->getEntries();
230 18
	    self::$original_entry = $entries[0];
231 18
	    $this->entry = $entries[0];
232
233 18
		self::$original_form = $gravityview_view->getForm();
234 18
		$this->form = $gravityview_view->getForm();
235 18
		$this->form_id = $this->entry['form_id'];
236 18
		$this->view_id = $gravityview_view->getViewId();
237 18
		$this->post_id = \GV\Utils::get( $post, 'ID', null );
238
239 18
		self::$nonce_key = GravityView_Edit_Entry::get_nonce_key( $this->view_id, $this->form_id, $this->entry['id'] );
240 18
	}
241
242
243
	/**
244
	 * Load required files and trigger edit flow
245
	 *
246
	 * Run when the is_edit_entry returns true.
247
	 *
248
	 * @param \GravityView_View_Data $gv_data GravityView Data object
249
	 * @param \GV\Entry   $entry   The Entry.
250
	 * @param \GV\View    $view    The View.
251
	 * @param \GV\Request $request The Request.
252
	 *
253
	 * @since develop Added $entry, $view, $request adhocs.
254
	 *
255
	 * @return void
256
	 */
257 19
	public function init( $gv_data = null, $entry = null, $view = null, $request = null ) {
258
259 19
		require_once( GFCommon::get_base_path() . '/form_display.php' );
260 19
		require_once( GFCommon::get_base_path() . '/entry_detail.php' );
261
262 19
		$this->setup_vars();
263
264 19
		if ( ! $gv_data ) {
265
			$gv_data = GravityView_View_Data::getInstance();
266
		}
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
			return;
272
		}
273
274
		// Sorry, you're not allowed here.
275 19
		if ( false === $this->user_can_edit_entry( true ) ) {
276 2
			gravityview()->log->error( 'User is not allowed to edit this entry; returning', array( 'data' => $this->entry ) );
277 2
			return;
278
		}
279
280 19
		$this->view = $view;
281
282 19
		$this->print_scripts();
283
284 19
		$this->process_save( $gv_data );
285
286 19
		$this->edit_entry_form();
287
288 19
	}
289
290
291
	/**
292
	 * Force Gravity Forms to output scripts as if it were in the admin
293
	 * @return void
294
	 */
295 18
	private function print_scripts() {
296 18
		$gravityview_view = GravityView_View::getInstance();
297
298 18
		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 18
		GFFormDisplay::enqueue_form_scripts( $gravityview_view->getForm(), false);
301
302 18
		wp_localize_script( 'gravityview-fe-view', 'gvGlobals', array( 'cookiepath' => COOKIEPATH ) );
303
304
		// Sack is required for images
305 18
		wp_print_scripts( array( 'sack', 'gform_gravityforms', 'gravityview-fe-view' ) );
306 18
	}
307
308
309
	/**
310
	 * Process edit entry form save
311
	 *
312
	 * @param array $gv_data The View data.
313
	 */
314 19
	private function process_save( $gv_data ) {
315
316 19
		if ( empty( $_POST ) || ! isset( $_POST['lid'] ) ) {
317 5
			return;
318
		}
319
320
		// Make sure the entry, view, and form IDs are all correct
321 18
		$valid = $this->verify_nonce();
322
323 18
		if ( !$valid ) {
324
			gravityview()->log->error( 'Nonce validation failed.' );
325
			return;
326
		}
327
328 18
		if ( $this->entry['id'] !== $_POST['lid'] ) {
329
			gravityview()->log->error( 'Entry ID did not match posted entry ID.' );
330
			return;
331
		}
332
333 18
		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 18
		$this->validate();
338
339 18
		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
341 18
			gravityview()->log->debug( 'Submission is valid.' );
342
343
			/**
344
			 * @hack This step is needed to unset the adminOnly from form fields, to add the calculation fields
345
			 */
346 18
			$form = $this->form_prepare_for_save();
347
348
			/**
349
			 * @hack to avoid the capability validation of the method save_lead for GF 1.9+
350
			 */
351 18
			unset( $_GET['page'] );
352
353 18
			$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
			 */
359 18
			unset( $this->entry['date_created'] );
360
361
			/**
362
			 * @action `gravityview/edit_entry/before_update` Perform an action after the entry has been updated using Edit Entry
363
			 * @since develop
364
			 * @param array $form Gravity Forms form array
365
			 * @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
			 */
369 18
			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 18
	        $this->unset_hidden_field_values();
375
			
376 18
			$this->entry['date_created'] = $date_created;
377
378
			// Process calculation fields
379 18
			$this->update_calculation_fields();
380
381
			// Perform actions normally performed after updating a lead
382 18
			$this->after_update();
383
384
	        /**
385
			 * Must be AFTER after_update()!
386
			 * @see https://github.com/gravityview/GravityView/issues/764
387
			 */
388 18
			$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
			 * @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 18
			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 18
	} // process_save
405
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
	 * @return void
414
	 */
415 17
	private function unset_hidden_field_values() {
416 17
	    global $wpdb;
417
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
		 * @param bool $unset_hidden_field_values Default: true
422
		 * @param GravityView_Edit_Entry_Render $this This object
423
		 */
424 17
		$unset_hidden_field_values = apply_filters( 'gravityview/edit_entry/unset_hidden_field_values', true, $this );
425
426 17
		$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 17
		if( ! $unset_hidden_field_values ) {
429
			return;
430
		}
431
432 17
		if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
433 17
			$entry_meta_table = GFFormsModel::get_entry_meta_table_name();
434 17
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $entry_meta_table WHERE entry_id=%d", $this->entry['id'] ) );
435
		} 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
440 17
	    foreach ( $this->entry as $input_id => $field_value ) {
441
442 17
			if ( ! is_numeric( $input_id ) ) {
443 17
				continue;
444
			}
445
446 17
		    $field = RGFormsModel::get_field( $this->form, $input_id );
447
448
		    // Reset fields that are hidden
449
		    // Don't pass $entry as fourth parameter; force using $_POST values to calculate conditional logic
450 17
		    if ( GFFormsModel::is_field_hidden( $this->form, $field, array(), NULL ) ) {
451
452 1
				$empty_value = $field->get_value_save_entry(
453 1
					is_array( $field->get_entry_inputs() ) ? array() : '',
454 1
					$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 1
					$empty_value = '';
460
				}
461
462 1
			    $lead_detail_id = GFFormsModel::get_lead_detail_id( $current_fields, $input_id );
463
464 1
			    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 1
			    $post_input_id = 'input_' . str_replace( '.', '_', $input_id );
469 1
			    $_POST[ $post_input_id ] = '';
470
		    }
471
	    }
472 17
	}
473
474
	/**
475
	 * Have GF handle file uploads
476
	 *
477
	 * Copy of code from GFFormDisplay::process_form()
478
	 *
479
	 * @param int $form_id
480
	 */
481 17
	private function process_save_process_files( $form_id ) {
482
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 16
			$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 17
		add_filter( "gform_save_field_value_$form_id", array( $this, 'save_field_value' ), 99, 5 );
494
495 17
		RGFormsModel::$uploaded_files[ $form_id ] = $files;
496 17
	}
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
	 *
503
	 * @since 1.20.1
504
	 *
505
	 * @param string $value Field value
506
	 * @param array $entry GF entry array
507
	 * @param GF_Field_FileUpload $field
508
	 * @param array $form GF form array
509
	 * @param string $input_id ID of the input being saved
510
	 *
511
	 * @return string
512
	 */
513 17
	public function save_field_value( $value = '', $entry = array(), $field = null, $form = array(), $input_id = '' ) {
514
515 17
		if ( ! $field || $field->type != 'fileupload' ) {
516 17
			return $value;
517
		}
518
519 1
		$input_name = 'input_' . str_replace( '.', '_', $input_id );
520
521 1
		if ( $field->multipleFiles ) {
522
			if ( empty( $value ) ) {
523
				return json_decode( $entry[ $input_id ], true );
524
			}
525
			return $value;
526
		}
527
528
		/** No file is being uploaded. */
529 1
		if ( empty( $_FILES[ $input_name ]['name'] ) ) {
530
			/** So return the original upload */
531 1
			return $entry[ $input_id ];
532
		}
533
534 1
		return $value;
535
	}
536
537
	/**
538
	 * Remove max_files validation (done on gravityforms.js) to avoid conflicts with GravityView
539
	 * Late validation done on self::custom_validation
540
	 *
541
	 * @param $plupload_init array Plupload settings
542
	 * @param $form_id
543
	 * @param $instance
544
	 * @return mixed
545
	 */
546 2
	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 2
		if( ! $this->is_edit_entry() ) {
548
			return $plupload_init;
549
		}
550
551 2
		$plupload_init['gf_vars']['max_files'] = 0;
552
553 2
		return $plupload_init;
554
	}
555
556
557
	/**
558
	 * Set visibility to visible and convert field input key to string
559
	 * @return array $form
560
	 */
561 17
	private function form_prepare_for_save() {
562
563 17
		$form = $this->filter_conditional_logic( $this->form );
564
565
	    /** @var GF_Field $field */
566 17
		foreach( $form['fields'] as $k => &$field ) {
567
568
			/**
569
			 * Remove the fields with calculation formulas before save to avoid conflicts with GF logic
570
			 * @since 1.16.3
571
			 * @var GF_Field $field
572
			 */
573 17
			if( $field->has_calculation() ) {
574 4
				unset( $form['fields'][ $k ] );
575
			}
576
577 17
			$field->adminOnly = false;
578
579 17
			if( isset( $field->inputs ) && is_array( $field->inputs ) ) {
580 2
				foreach( $field->inputs as $key => $input ) {
581 2
				    $field->inputs[ $key ][ 'id' ] = (string)$input['id'];
582
				}
583
			}
584
		}
585
586 17
		$form['fields'] = array_values( $form['fields'] );
587
588 17
		return $form;
589
	}
590
591 17
	private function update_calculation_fields() {
592 17
		global $wpdb;
593
594 17
		$form = self::$original_form;
595 17
		$update = false;
596
597
		// get the most up to date entry values
598 17
		$entry = GFAPI::get_entry( $this->entry['id'] );
599
600 17
		if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
601 17
			$entry_meta_table = GFFormsModel::get_entry_meta_table_name();
602 17
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $entry_meta_table WHERE entry_id=%d", $entry['id'] ) );
603
		} else {
604
			$lead_detail_table = GFFormsModel::get_lead_details_table_name();
605
			$current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $lead_detail_table WHERE lead_id=%d", $entry['id'] ) );
606
		}
607
608
609 17
		if ( ! empty( $this->fields_with_calculation ) ) {
610 5
			$allowed_fields = $this->get_configured_edit_fields( $form, $this->view_id );
611 5
			$allowed_fields = wp_list_pluck( $allowed_fields, 'id' );
612
613 5
			foreach ( $this->fields_with_calculation as $field ) {
614
615 5
				if ( in_array( $field->id, $this->unset_hidden_calculations, true ) ) {
616 1
					continue;
617
				}
618
619 5
				$inputs = $field->get_entry_inputs();
620 5
				if ( is_array( $inputs ) ) {
621 4
				    foreach ( $inputs as $input ) {
622 4
						list( $field_id, $input_id ) = rgexplode( '.', $input['id'], 2 );
623
624 4
						if ( 'product' === $field->type ) {
625 4
							$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 4
								$_POST[ $input_name ] = $entry[ $input['id'] ];
631
							}
632
						} else {
633
							// Set to what it previously was if it's not editable
634
							if ( ! in_array( $field_id, $allowed_fields ) ) {
635
								$_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 4
						GFFormsModel::save_input( $form, $field, $entry, $current_fields, $input['id'] );
640
				    }
641
				} else {
642
					// Set to what it previously was if it's not editable
643 3
					if ( ! in_array( $field->id, $allowed_fields ) ) {
644 2
						$_POST[ 'input_' . $field->id ] = $entry[ $field->id ];
645
					}
646 3
					GFFormsModel::save_input( $form, $field, $entry, $current_fields, $field->id );
647
				}
648
			}
649
650 5
			if ( method_exists( 'GFFormsModel', 'commit_batch_field_operations' ) ) {
651 5
				GFFormsModel::commit_batch_field_operations();
652
			}
653
		}
654 17
	}
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
	 * @uses set_post_thumbnail
665
	 *
666
	 * @param array $form GF Form array
667
	 * @param GF_Field $field GF Field
668
	 * @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 1
	private function update_post_image( $form, $field, $field_id, $value, $entry, $post_id ) {
676
677 1
		$input_name = 'input_' . $field_id;
678
679 1
		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
			 * 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
			 */
707
			require_once GRAVITYVIEW_DIR . 'includes/class-gravityview-gfformsmodel.php';
708
			$media_id = GravityView_GFFormsModel::media_handle_upload( $img_url, $post_id, $image_meta );
709
710
			// is this field set as featured image?
711
			if ( $media_id && $field->postFeaturedImage ) {
712
				set_post_thumbnail( $post_id, $media_id );
713
			}
714
715 1
		} elseif ( ! empty( $_POST[ $input_name ] ) && is_array( $value ) ) {
716
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 1
			$img_description = stripslashes_deep( \GV\Utils::_POST( $input_name . '_7' ) );
721
722 1
			$value = ! empty( $img_url ) ? $img_url . "|:|" . $img_title . "|:|" . $img_caption . "|:|" . $img_description : '';
723
724 1
			if ( $field->postFeaturedImage ) {
725
726
				$image_meta = array(
727 1
					'ID' => get_post_thumbnail_id( $post_id ),
728 1
					'post_title' => $img_title,
729 1
					'post_excerpt' => $img_caption,
730 1
					'post_content' => $img_description,
731
				);
732
733
				// update image title, caption or description
734 1
				wp_update_post( $image_meta );
735
			}
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
746 1
		return $value;
747
	}
748
749
	/**
750
	 * Loop through the fields being edited and if they include Post fields, update the Entry's post object
751
	 *
752
	 * @param array $form Gravity Forms form
753
	 *
754
	 * @return void
755
	 */
756 17
	private function maybe_update_post_fields( $form ) {
757
758 17
		if( empty( $this->entry['post_id'] ) ) {
759 16
	        gravityview()->log->debug( 'This entry has no post fields. Continuing...' );
760 16
			return;
761
		}
762
763 1
		$post_id = $this->entry['post_id'];
764
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
			return;
769
		}
770
771 1
		$update_entry = false;
772
773 1
		$updated_post = $original_post = get_post( $post_id );
774
775 1
		foreach ( $this->entry as $field_id => $value ) {
776
777 1
			$field = RGFormsModel::get_field( $form, $field_id );
778
779 1
			if( ! $field ) {
780 1
				continue;
781
			}
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 1
				$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 1
				$entry_tmp = $this->entry;
790 1
				$entry_tmp["{$field_id}"] = $value;
791
792 1
				switch( $field->type ) {
793
794 1
				    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
				        unset( $post_title );
802
				        break;
803
804 1
				    case 'post_content':
805
				        $post_content = $value;
806
				        if ( \GV\Utils::get( $form, 'postContentTemplateEnabled' ) ) {
807
				            $post_content = $this->fill_post_template( $form['postContentTemplate'], $form, $entry_tmp, true );
808
				        }
809
				        $updated_post->post_content = $post_content;
810
				        unset( $post_content );
811
				        break;
812 1
				    case 'post_excerpt':
813
				        $updated_post->post_excerpt = $value;
814
				        break;
815 1
				    case 'post_tags':
816
				        wp_set_post_tags( $post_id, $value, false );
817
				        break;
818 1
				    case 'post_category':
819
				        break;
820 1
				    case 'post_custom_field':
821
						if ( is_array( $value ) && ( floatval( $field_id ) !== floatval( $field->id ) ) ) {
822
							$value = $value[ $field_id ];
823
						}
824
825
				        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
831
				        update_post_meta( $post_id, $field->postCustomFieldName, $value );
832
				        break;
833
834 1
				    case 'post_image':
835 1
				        $value = $this->update_post_image( $form, $field, $field_id, $value, $this->entry, $post_id );
836 1
				        break;
837
838
				}
839
840
				// update entry after
841 1
				$this->entry["{$field_id}"] = $value;
842
843 1
				$update_entry = true;
844
845 1
				unset( $entry_tmp );
846
			}
847
848
		}
849
850 1
		if( $update_entry ) {
851
852 1
			$return_entry = GFAPI::update_entry( $this->entry );
853
854 1
			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
860
		}
861
862 1
		$return_post = wp_update_post( $updated_post, true );
863
864 1
		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 1
			gravityview()->log->debug( 'Updating the post content for post #{post_id} succeeded', array( 'post_id' => $post_id, 'data' => $updated_post ) );
869
		}
870 1
	}
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
905
906
	/**
907
	 * Perform actions normally performed after updating a lead
908
	 *
909
	 * @since 1.8
910
	 *
911
	 * @see GFEntryDetail::lead_detail_page()
912
	 *
913
	 * @return void
914
	 */
915 17
	private function after_update() {
916
917 17
		do_action( 'gform_after_update_entry', $this->form, $this->entry['id'], self::$original_entry );
918 17
		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 17
		$entry = RGFormsModel::get_lead( $this->entry['id'] );
922
923 17
		$entry = GFFormsModel::set_entry_meta( $entry, self::$original_form );
924
925 17
		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
			// we have just updated.
928
			foreach ($this->form['fields'] as $key => $field) {
929
				GFFormsModel::refresh_lead_field_value( $entry['id'], $field->id );
930
			}
931
		}
932
933
		/**
934
		 * Maybe process feeds.
935
		 *
936
		 * @since develop
937
		 */
938 17
		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 1
						if ( method_exists( $registered_feed, 'get_instance' ) ) {
945 1
							$registered_feed = call_user_func( array( $registered_feed, 'get_instance' ) );
946 1
							$registered_feeds[ $registered_feed->get_slug() ] = $registered_feed;
947
						}
948
					}
949
				}
950 1
				foreach ( $feeds as $feed ) {
951 1
					if ( in_array( $feed['id'], $allowed_feeds ) ) {
952 1
						if ( $feed_object = \GV\Utils::get( $registered_feeds, $feed['addon_slug'] ) ) {
953 1
							$returned_entry = $feed_object->process_feed( $feed, $entry, self::$original_form );
954 1
							if ( is_array( $returned_entry ) && rgar( $returned_entry, 'id' ) ) {
955
								$entry = $returned_entry;
956
							}
957
958 1
							do_action( 'gform_post_process_feed', $feed, $entry, self::$original_form, $feed_object );
959 1
							$slug = $feed_object->get_slug();
960 1
							do_action( "gform_{$slug}_post_process_feed", $feed, $entry, self::$original_form, $feed_object );
961
						}
962
					}
963
				}
964
			}
965
		}
966
967 17
		$this->entry = $entry;
968 17
	}
969
970
971
	/**
972
	 * Display the Edit Entry form
973
	 *
974
	 * @return void
975
	 */
976 18
	public function edit_entry_form() {
977
978
		?>
979
980
		<div class="gv-edit-entry-wrapper"><?php
981
982 18
			$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
			 */
988 18
			echo gravityview_strip_whitespace( $javascript );
989
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 18
				    $edit_entry_title = apply_filters('gravityview_edit_entry_title', __('Edit Entry', 'gravityview'), $this );
999
1000 18
				    echo esc_attr( $edit_entry_title );
1001
			?></span>
1002
			</h2>
1003
1004
			<?php $this->maybe_print_message(); ?>
1005
1006
			<?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
1010
				<?php
1011
1012 18
				wp_nonce_field( self::$nonce_key, self::$nonce_key );
1013
1014 18
				wp_nonce_field( self::$nonce_field, self::$nonce_field, false );
1015
1016
				// Print the actual form HTML
1017 18
				$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
	/**
1034
	 * Display success or error message if the form has been submitted
1035
	 *
1036
	 * @uses GVCommon::generate_notice
1037
	 *
1038
	 * @since 1.16.2.2
1039
	 *
1040
	 * @return void
1041
	 */
1042 18
	private function maybe_print_message() {
1043
1044 18
		if ( \GV\Utils::_POST( 'action' ) === 'update' ) {
1045
1046 17
			$back_link = remove_query_arg( array( 'page', 'view', 'edit' ) );
1047
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
				$message = apply_filters("gform_validation_message_{$this->form['id']}", apply_filters("gform_validation_message", $validation_message, $this->form), $this->form);
1053
1054
				echo GVCommon::generate_notice( $message , 'gv-error' );
1055
1056
			} else {
1057 17
				$view = \GV\View::by_id( $this->view_id );
1058 17
				$edit_redirect = $view->settings->get( 'edit_redirect' );
1059 17
				$edit_redirect_url = $view->settings->get( 'edit_redirect_url' );
1060
1061
				switch ( $edit_redirect ) {
1062
1063 17
                    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 16
                    case '1':
1069 1
	                    $redirect_url = $directory_link = GravityView_API::directory_link();
1070 1
	                    $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 1
	                    break;
1072
1073 15
                    case '2':
1074 1
	                    $redirect_url = $edit_redirect_url;
1075 1
	                    $redirect_url = GFCommon::replace_variables( $redirect_url, $this->form, $this->entry, false, false, false, 'text' );
1076 1
	                    $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 1
                        break;
1078
1079 14
                    case '':
1080
                    default:
1081 14
					    $entry_updated_message = sprintf( esc_attr__('Entry Updated. %sReturn to Entry%s', 'gravityview'), '<a href="'. esc_url( $back_link ) .'">', '</a>' );
1082 14
                        break;
1083
				}
1084
1085 17
				if ( isset( $redirect_url ) ) {
1086 3
					$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
1089
				/**
1090
				 * @filter `gravityview/edit_entry/success` Modify the edit entry success message (including the anchor link)
1091
				 * @since 1.5.4
1092
				 * @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 17
				$message = apply_filters( 'gravityview/edit_entry/success', $entry_updated_message , $this->view_id, $this->entry, $back_link );
1098
1099 17
				echo GVCommon::generate_notice( $message );
1100
			}
1101
1102
		}
1103 18
	}
1104
1105
	/**
1106
	 * Display the Edit Entry form in the original Gravity Forms format
1107
	 *
1108
	 * @since 1.9
1109
	 *
1110
	 * @return void
1111
	 */
1112 18
	private function render_edit_form() {
1113
1114
		/**
1115
		 * @action `gravityview/edit-entry/render/before` Before rendering the Edit Entry form
1116
		 * @since 1.17
1117
		 * @param GravityView_Edit_Entry_Render $this
1118
		 */
1119 18
		do_action( 'gravityview/edit-entry/render/before', $this );
1120
1121 18
		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 18
		add_filter( 'gform_next_button', array( $this, 'render_form_buttons' ) );
1124 18
		add_filter( 'gform_previous_button', array( $this, 'render_form_buttons' ) );
1125 18
		add_filter( 'gform_disable_view_counter', '__return_true' );
1126
1127 18
		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
1130
		// We need to remove the fake $_GET['page'] arg to avoid rendering form as if in admin.
1131 18
		unset( $_GET['page'] );
1132
1133 18
		$this->show_next_button = false;
1134 18
		$this->show_previous_button = false;
1135
1136
		// TODO: Verify multiple-page forms
1137 18
		if ( GFCommon::has_pages( $this->form ) && apply_filters( 'gravityview/features/paged-edit', false ) ) {
1138
			if ( intval( $page_number = \GV\Utils::_POST( 'gform_source_page_number_' . $this->form['id'], 0 ) ) ) {
1139
1140
				$labels = array(
1141
					'cancel'   => __( 'Cancel', 'gravityview' ),
1142
					'submit'   => __( 'Update', 'gravityview' ),
1143
					'next'     => __( 'Next', 'gravityview' ),
1144
					'previous' => __( 'Previous', 'gravityview' ),
1145
				);
1146
1147
				/**
1148
				* @filter `gravityview/edit_entry/button_labels` Modify the cancel/submit buttons' labels
1149
				* @since 1.16.3
1150
				* @param array $labels Default button labels associative array
1151
				* @param array $form The Gravity Forms form
1152
				* @param array $entry The Gravity Forms entry
1153
				* @param int $view_id The current View ID
1154
				*/
1155
				$labels = apply_filters( 'gravityview/edit_entry/button_labels', $labels, $this->form, $this->entry, $this->view_id );
1156
1157
				GFFormDisplay::$submission[ $this->form['id'] ][ 'form' ] = $this->form;
1158
				GFFormDisplay::$submission[ $this->form['id'] ][ 'is_valid' ] = true;
1159
1160
				if ( \GV\Utils::_POST( 'save' ) === $labels['next'] ) {
1161
					$page_number++;
1162 18
				} elseif ( \GV\Utils::_POST( 'save' ) === $labels['previous'] ) {
1163
					$page_number--;
1164
				}
1165 18
1166
				GFFormDisplay::$submission[ $this->form['id'] ][ 'page_number' ] = $page_number;
1167 18
			}
1168
1169 18
			if ( ( $page_number = intval( $page_number ) ) < 2 ) {
1170
				$this->show_next_button = true; // First page
1171 18
			}
1172 18
1173 18
			$last_page = \GFFormDisplay::get_max_page_number( $this->form );
1174 18
1175 18
			$has_more_pages = $page_number < $last_page;
1176 18
1177 18
			if ( $has_more_pages ) {
1178
				$this->show_next_button = true; // Not the last page
1179 18
			} else {
1180
				$this->show_update_button = true; // The last page
1181
			}
1182
1183
			if ( $page_number > 1 ) {
1184
				$this->show_previous_button = true; // Not the first page
1185
			}
1186 18
		} else {
1187 18
			$this->show_update_button = true;
1188
		}
1189
1190
		ob_start(); // Prevent PHP warnings possibly caused by prefilling list fields for conditional logic
1191
1192
		$html = GFFormDisplay::get_form( $this->form['id'], false, false, true, $this->entry );
1193
1194 18
		ob_get_clean();
1195 18
1196
	    remove_filter( 'gform_pre_render', array( $this, 'filter_modify_form_fields' ), 5000 );
1197
		remove_filter( 'gform_submit_button', array( $this, 'render_form_buttons' ) );
1198
		remove_filter( 'gform_next_button', array( $this, 'render_form_buttons' ) );
1199
		remove_filter( 'gform_previous_button', array( $this, 'render_form_buttons' ) );
1200
		remove_filter( 'gform_disable_view_counter', '__return_true' );
1201
		remove_filter( 'gform_field_input', array( $this, 'verify_user_can_edit_post' ), 5 );
1202
		remove_filter( 'gform_field_input', array( $this, 'modify_edit_field_input' ), 10 );
1203
1204
		echo $html;
1205
1206
		/**
1207
		 * @action `gravityview/edit-entry/render/after` After rendering the Edit Entry form
1208
		 * @since 1.17
1209
		 * @param GravityView_Edit_Entry_Render $this
1210
		 */
1211
		do_action( 'gravityview/edit-entry/render/after', $this );
1212 18
	}
1213
1214
	/**
1215 18
	 * Display the Update/Cancel/Delete buttons for the Edit Entry form
1216 17
	 * @since 1.8
1217
	 * @return string
1218 4
	 */
1219
	public function render_form_buttons() {
1220
		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...
1221 18
	}
1222
1223 18
1224
	/**
1225
	 * Modify the form fields that are shown when using GFFormDisplay::get_form()
1226 18
	 *
1227 18
	 * By default, all fields will be shown. We only want the Edit Tab configured fields to be shown.
1228
	 *
1229
	 * @param array $form
1230 18
	 * @param boolean $ajax Whether in AJAX mode
1231
	 * @param array|string $field_values Passed parameters to the form
1232 18
	 *
1233
	 * @since 1.9
1234
	 *
1235
	 * @return array Modified form array
1236
	 */
1237
	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...
1238
1239
		// In case we have validated the form, use it to inject the validation results into the form render
1240
		if( isset( $this->form_after_validation ) && $this->form_after_validation['id'] === $form['id'] ) {
1241
			$form = $this->form_after_validation;
1242
		} else {
1243
			$form['fields'] = $this->get_configured_edit_fields( $form, $this->view_id );
1244
		}
1245
1246
		$form = $this->filter_conditional_logic( $form );
1247
1248 18
		$form = $this->prefill_conditional_logic( $form );
1249
1250 18
		// for now we don't support Save and Continue feature.
1251 18
		if( ! self::$supports_save_and_continue ) {
1252
	        unset( $form['save'] );
1253
		}
1254 2
1255
		$form = $this->unselect_default_values( $form );
1256
1257 2
		return $form;
1258
	}
1259
1260
	/**
1261
	 * 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.
1262
	 *
1263 1
	 * @since 1.16.2.2
1264
	 *
1265 1
	 * @param string $field_content Always empty. Returning not-empty overrides the input.
1266
	 * @param GF_Field $field
1267
	 * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1268
	 * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1269
	 * @param int $form_id Form ID
1270
	 *
1271
	 * @return string If error, the error message. If no error, blank string (modify_edit_field_input() runs next)
1272
	 */
1273 2
	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...
1274 1
1275
		if( ! GFCommon::is_post_field( $field ) ) {
1276
			return $field_content;
1277 2
		}
1278
1279
        $message = null;
1280
1281
        // First, make sure they have the capability to edit the post.
1282
        if( false === current_user_can( 'edit_post', $this->entry['post_id'] ) ) {
1283
1284
            /**
1285
             * @filter `gravityview/edit_entry/unsupported_post_field_text` Modify the message when someone isn't able to edit a post
1286
             * @param string $message The existing "You don't have permission..." text
1287
             */
1288
            $message = apply_filters('gravityview/edit_entry/unsupported_post_field_text', __('You don&rsquo;t have permission to edit this post.', 'gravityview') );
1289
1290
        } elseif( null === get_post( $this->entry['post_id'] ) ) {
1291
            /**
1292 18
             * @filter `gravityview/edit_entry/no_post_text` Modify the message when someone is editing an entry attached to a post that no longer exists
1293
             * @param string $message The existing "This field is not editable; the post no longer exists." text
1294 18
             */
1295
            $message = apply_filters('gravityview/edit_entry/no_post_text', __('This field is not editable; the post no longer exists.', 'gravityview' ) );
1296
        }
1297
1298
        if( $message ) {
1299 18
            $field_content = sprintf('<div class="ginput_container ginput_container_' . $field->type . '">%s</div>', wpautop( $message ) );
1300 18
        }
1301
1302 18
        return $field_content;
1303 18
	}
1304
1305 1
	/**
1306
	 *
1307
	 * Fill-in the saved values into the form inputs
1308
	 *
1309 18
	 * @param string $field_content Always empty. Returning not-empty overrides the input.
1310
	 * @param GF_Field $field
1311 18
	 * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1312
	 * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1313
	 * @param int $form_id Form ID
1314 18
	 *
1315
	 * @return mixed
1316 18
	 */
1317
	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...
1318
1319 18
		$gv_field = GravityView_Fields::get_associated_field( $field );
1320 3
1321
		// If the form has been submitted, then we don't need to pre-fill the values,
1322 18
		// Except for fileupload type and when a field input is overridden- run always!!
1323
		if(
1324
			( $this->is_edit_entry_submission() && !in_array( $field->type, array( 'fileupload', 'post_image' ) ) )
1325
			&& false === ( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) )
1326 18
			&& ! GFCommon::is_product_field( $field->type )
1327
			|| ! empty( $field_content )
1328 18
			|| in_array( $field->type, array( 'honeypot' ) )
1329
		) {
1330
	        return $field_content;
1331
		}
1332 18
1333
		// SET SOME FIELD DEFAULTS TO PREVENT ISSUES
1334
		$field->adminOnly = false; /** @see GFFormDisplay::get_counter_init_script() need to prevent adminOnly */
1335
1336
		$field_value = $this->get_field_value( $field );
1337
1338
	    // Prevent any PHP warnings, like undefined index
1339
	    ob_start();
1340
1341
	    $return = null;
1342 18
1343
		/** @var GravityView_Field $gv_field */
1344
		if( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) ) {
1345
			$return = $gv_field->get_field_input( $this->form, $field_value, $this->entry, $field );
1346
		} else {
1347
	        $return = $field->get_field_input( $this->form, $field_value, $this->entry );
1348
	    }
1349
1350 18
	    // If there was output, it's an error
1351
	    $warnings = ob_get_clean();
1352
1353 18
	    if( !empty( $warnings ) ) {
1354
		    gravityview()->log->error( '{warning}', array( 'warning' => $warnings, 'data' => $field_value ) );
1355 3
	    }
1356
1357
		return $return;
1358 3
	}
1359
1360 3
	/**
1361
	 * Modify the value for the current field input
1362 3
	 *
1363
	 * @param GF_Field $field
1364 3
	 *
1365 3
	 * @return array|mixed|string
1366 3
	 */
1367
	private function get_field_value( $field ) {
1368
1369
		/**
1370
		 * @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.
1371 3
		 * @param boolean True: override saved values; False: don't override (default)
1372
		 * @param $field GF_Field object Gravity Forms field object
1373 3
		 * @since 1.13
1374
		 */
1375
		$override_saved_value = apply_filters( 'gravityview/edit_entry/pre_populate/override', false, $field );
1376
1377 18
		// We're dealing with multiple inputs (e.g. checkbox) but not time or date (as it doesn't store data in input IDs)
1378
		if( isset( $field->inputs ) && is_array( $field->inputs ) && !in_array( $field->type, array( 'time', 'date' ) ) ) {
1379
1380 18
			$field_value = array();
1381
1382
			// only accept pre-populated values if the field doesn't have any choice selected.
1383
			$allow_pre_populated = $field->allowsPrepopulate;
1384 18
1385
			foreach ( (array)$field->inputs as $input ) {
1386
1387 18
				$input_id = strval( $input['id'] );
1388
1389
				if ( isset( $this->entry[ $input_id ] ) && ! gv_empty( $this->entry[ $input_id ], false, false ) ) {
1390
				    $field_value[ $input_id ] =  'post_category' === $field->type ? GFCommon::format_post_category( $this->entry[ $input_id ], true ) : $this->entry[ $input_id ];
1391
				    $allow_pre_populated = false;
1392
				}
1393
1394
			}
1395
1396
			$pre_value = $field->get_value_submission( array(), false );
1397
1398 18
			$field_value = ! $allow_pre_populated && ! ( $override_saved_value && !gv_empty( $pre_value, false, false ) ) ? $field_value : $pre_value;
1399
1400
		} else {
1401
1402
			$id = intval( $field->id );
1403
1404
			// get pre-populated value if exists
1405
			$pre_value = $field->allowsPrepopulate ? GFFormsModel::get_parameter_value( $field->inputName, array(), $field ) : '';
1406
1407
			// saved field entry value (if empty, fallback to the pre-populated value, if exists)
1408 18
			// or pre-populated value if not empty and set to override saved value
1409
			$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;
1410
1411
			// in case field is post_category but inputType is select, multi-select or radio, convert value into array of category IDs.
1412
			if ( 'post_category' === $field->type && !gv_empty( $field_value, false, false ) ) {
1413
				$categories = array();
1414
				foreach ( explode( ',', $field_value ) as $cat_string ) {
1415
				    $categories[] = GFCommon::format_post_category( $cat_string, true );
1416
				}
1417
				$field_value = 'multiselect' === $field->get_input_type() ? $categories : implode( '', $categories );
1418 18
			}
1419
1420 18
		}
1421
1422
		// if value is empty get the default value if defined
1423
		$field_value = $field->get_value_default_if_empty( $field_value );
1424
1425
	    /**
1426
	     * @filter `gravityview/edit_entry/field_value` Change the value of an Edit Entry field, if needed
1427
	     * @since 1.11
1428
	     * @since 1.20 Added third param
1429
	     * @param mixed $field_value field value used to populate the input
1430
	     * @param object $field Gravity Forms field object ( Class GF_Field )
1431
	     * @param GravityView_Edit_Entry_Render $this Current object
1432
	     */
1433 17
	    $field_value = apply_filters( 'gravityview/edit_entry/field_value', $field_value, $field, $this );
1434
1435 17
	    /**
1436
	     * @filter `gravityview/edit_entry/field_value_{field_type}` Change the value of an Edit Entry field for a specific field type
1437
	     * @since 1.17
1438
	     * @since 1.20 Added third param
1439
	     * @param mixed $field_value field value used to populate the input
1440 17
	     * @param GF_Field $field Gravity Forms field object
1441
	     * @param GravityView_Edit_Entry_Render $this Current object
1442
	     */
1443
	    $field_value = apply_filters( 'gravityview/edit_entry/field_value_' . $field->type , $field_value, $field, $this );
1444 17
1445 17
		return $field_value;
1446
	}
1447
1448 17
1449
	// ---- Entry validation
1450
1451
	/**
1452
	 * Add field keys that Gravity Forms expects.
1453
	 *
1454
	 * @see GFFormDisplay::validate()
1455
	 * @param  array $form GF Form
1456
	 * @return array       Modified GF Form
1457 17
	 */
1458
	public function gform_pre_validation( $form ) {
1459
1460 1
		if( ! $this->verify_nonce() ) {
1461
			return $form;
1462 1
		}
1463 1
1464
		// Fix PHP warning regarding undefined index.
1465 1
		foreach ( $form['fields'] as &$field) {
1466
1467
			// This is because we're doing admin form pretending to be front-end, so Gravity Forms
1468 1
			// expects certain field array items to be set.
1469 1
			foreach ( array( 'noDuplicates', 'adminOnly', 'inputType', 'isRequired', 'enablePrice', 'inputs', 'allowedExtensions' ) as $key ) {
1470
	            $field->{$key} = isset( $field->{$key} ) ? $field->{$key} : NULL;
1471
			}
1472
1473 1
			switch( RGFormsModel::get_input_type( $field ) ) {
1474 1
1475 1
				/**
1476
				 * 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.
1477
				 *
1478
				 * 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.
1479
				 *
1480
				 * @hack
1481 1
				 */
1482
				case 'fileupload':
1483
1484
				    // Set the previous value
1485 1
				    $entry = $this->get_entry();
1486
1487
				    $input_name = 'input_'.$field->id;
1488
				    $form_id = $form['id'];
1489 1
1490
				    $value = NULL;
1491
1492 1
				    // Use the previous entry value as the default.
1493
				    if( isset( $entry[ $field->id ] ) ) {
1494
				        $value = $entry[ $field->id ];
1495
				    }
1496
1497
				    // If this is a single upload file
1498
				    if( !empty( $_FILES[ $input_name ] ) && !empty( $_FILES[ $input_name ]['name'] ) ) {
1499 1
				        $file_path = GFFormsModel::get_file_upload_path( $form['id'], $_FILES[ $input_name ]['name'] );
1500
				        $value = $file_path['url'];
1501
1502
				    } else {
1503 1
1504 1
				        // Fix PHP warning on line 1498 of form_display.php for post_image fields
1505
				        // Fix PHP Notice:  Undefined index:  size in form_display.php on line 1511
1506 1
				        $_FILES[ $input_name ] = array('name' => '', 'size' => '' );
1507
1508 17
				    }
1509
1510 12
				    if ( \GV\Utils::get( $field, "multipleFiles" ) ) {
1511 7
1512
				        // If there are fresh uploads, process and merge them.
1513 12
				        // Otherwise, use the passed values, which should be json-encoded array of URLs
1514
				        if( isset( GFFormsModel::$uploaded_files[$form_id][$input_name] ) ) {
1515
				            $value = empty( $value ) ? '[]' : $value;
1516
				            $value = stripslashes_deep( $value );
1517
				            $value = GFFormsModel::prepare_value( $form, $field, $value, $input_name, $entry['id'], array());
1518 17
				        }
1519
1520
				    } else {
1521
1522
				        // A file already exists when editing an entry
1523
				        // We set this to solve issue when file upload fields are required.
1524
				        GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] = $value;
1525
1526
				    }
1527
1528
				    $this->entry[ $input_name ] = $value;
1529 18
				    $_POST[ $input_name ] = $value;
1530
1531
				    break;
1532
1533
				case 'number':
1534
				    // Fix "undefined index" issue at line 1286 in form_display.php
1535
				    if( !isset( $_POST['input_'.$field->id ] ) ) {
1536 18
				        $_POST['input_'.$field->id ] = NULL;
1537 18
				    }
1538
				    break;
1539
			}
1540
1541
		}
1542
1543
		return $form;
1544
	}
1545
1546
1547
	/**
1548 18
	 * Process validation for a edit entry submission
1549
	 *
1550
	 * Sets the `is_valid` object var
1551 18
	 *
1552 18
	 * @return void
1553
	 */
1554
	private function validate() {
1555
1556 18
		/**
1557
		 * If using GF User Registration Add-on, remove the validation step, otherwise generates error when updating the entry
1558
		 * GF User Registration Add-on version > 3.x has a different class name
1559 18
		 * @since 1.16.2
1560
		 */
1561 18
		if ( class_exists( 'GF_User_Registration' ) ) {
1562
			remove_filter( 'gform_validation', array( GF_User_Registration::get_instance(), 'validate' ) );
1563 18
		} else  if ( class_exists( 'GFUser' ) ) {
1564 18
			remove_filter( 'gform_validation', array( 'GFUser', 'user_registration_validation' ) );
1565
		}
1566
1567
1568
		/**
1569
		 * For some crazy reason, Gravity Forms doesn't validate Edit Entry form submissions.
1570
		 * You can enter whatever you want!
1571
		 * We try validating, and customize the results using `self::custom_validation()`
1572
		 */
1573
		add_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10, 4);
1574
1575
		// Needed by the validate funtion
1576
		$failed_validation_page = NULL;
1577
		$field_values = RGForms::post( 'gform_field_values' );
1578 18
1579
		// Prevent entry limit from running when editing an entry, also
1580 18
		// prevent form scheduling from preventing editing
1581
		unset( $this->form['limitEntries'], $this->form['scheduleForm'] );
1582 18
1583
		// Hide fields depending on Edit Entry settings
1584 18
		$this->form['fields'] = $this->get_configured_edit_fields( $this->form, $this->view_id );
1585
1586 18
		$this->is_valid = GFFormDisplay::validate( $this->form, $field_values, 1, $failed_validation_page );
1587
1588 18
		remove_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10 );
1589 18
	}
1590
1591
1592 18
	/**
1593
	 * Make validation work for Edit Entry
1594
	 *
1595 18
	 * Because we're calling the GFFormDisplay::validate() in an unusual way (as a front-end
1596 18
	 * form pretending to be a back-end form), validate() doesn't know we _can't_ edit post
1597
	 * fields. This goes through all the fields and if they're an invalid post field, we
1598
	 * set them as valid. If there are still issues, we'll return false.
1599 2
	 *
1600
	 * @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...
1601
	 * @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...
1602
	 */
1603
	public function custom_validation( $validation_results ) {
1604
1605 2
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results: ', array( 'data' => $validation_results ) );
1606
1607
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] $_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
1608
1609
		$gv_valid = true;
1610
1611
		foreach ( $validation_results['form']['fields'] as $key => &$field ) {
1612
1613
			$value = RGFormsModel::get_field_value( $field );
1614
			$field_type = RGFormsModel::get_input_type( $field );
1615
1616
			// Validate always
1617
			switch ( $field_type ) {
1618
1619
1620
				case 'fileupload' :
1621
				case 'post_image':
1622
1623
				    // in case nothing is uploaded but there are already files saved
1624
				    if( !empty( $field->failed_validation ) && !empty( $field->isRequired ) && !empty( $value ) ) {
1625
				        $field->failed_validation = false;
1626
				        unset( $field->validation_message );
1627
				    }
1628
1629
				    // validate if multi file upload reached max number of files [maxFiles] => 2
1630
				    if( \GV\Utils::get( $field, 'maxFiles') && \GV\Utils::get( $field, 'multipleFiles') ) {
1631
1632
				        $input_name = 'input_' . $field->id;
1633
				        //uploaded
1634 2
				        $file_names = isset( GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] : array();
1635
1636
				        //existent
1637
				        $entry = $this->get_entry();
1638
				        $value = NULL;
1639 18
				        if( isset( $entry[ $field->id ] ) ) {
1640
				            $value = json_decode( $entry[ $field->id ], true );
1641 1
				        }
1642
1643 1
				        // count uploaded files and existent entry files
1644
				        $count_files = ( is_array( $file_names ) ? count( $file_names ) : 0 ) +
1645
						               ( is_array( $value ) ? count( $value ) : 0 );
1646 1
1647
				        if( $count_files > $field->maxFiles ) {
1648
				            $field->validation_message = __( 'Maximum number of files reached', 'gravityview' );
1649 1
				            $field->failed_validation = 1;
1650
				            $gv_valid = false;
1651
1652
				            // in case of error make sure the newest upload files are removed from the upload input
1653
				            GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ] = null;
1654
				        }
1655
1656
				    }
1657 1
1658
1659
				    break;
1660
1661
			}
1662
1663 1
			// This field has failed validation.
1664
			if( !empty( $field->failed_validation ) ) {
1665
1666
				gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field is invalid.', array( 'data' => array( 'field' => $field, 'value' => $value ) ) );
1667
1668
				switch ( $field_type ) {
1669
1670
				    // Captchas don't need to be re-entered.
1671
				    case 'captcha':
1672
1673
				        // Post Image fields aren't editable, so we un-fail them.
1674
				    case 'post_image':
1675
				        $field->failed_validation = false;
1676
				        unset( $field->validation_message );
1677
				        break;
1678
1679
				}
1680
1681
				// You can't continue inside a switch, so we do it after.
1682 1
				if( empty( $field->failed_validation ) ) {
1683
				    continue;
1684
				}
1685
1686
				// checks if the No Duplicates option is not validating entry against itself, since
1687
				// we're editing a stored entry, it would also assume it's a duplicate.
1688 1
				if( !empty( $field->noDuplicates ) ) {
1689
1690
				    $entry = $this->get_entry();
1691
1692
				    // If the value of the entry is the same as the stored value
1693
				    // Then we can assume it's not a duplicate, it's the same.
1694 18
				    if( !empty( $entry ) && $value == $entry[ $field->id ] ) {
1695
				        //if value submitted was not changed, then don't validate
1696 18
				        $field->failed_validation = false;
1697
1698
				        unset( $field->validation_message );
1699 18
1700
				        gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field not a duplicate; it is the same entry.', array( 'data' => $entry ) );
1701 18
1702
				        continue;
1703
				    }
1704
				}
1705
1706
				// if here then probably we are facing the validation 'At least one field must be filled out'
1707
				if( GFFormDisplay::is_empty( $field, $this->form_id  ) && empty( $field->isRequired ) ) {
1708
				    unset( $field->validation_message );
1709
	                $field->validation_message = false;
1710 2
				    continue;
1711
				}
1712 2
1713
				$gv_valid = false;
1714 1
1715
			}
1716
1717 2
		}
1718
1719
		$validation_results['is_valid'] = $gv_valid;
1720
1721
		gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results.', array( 'data' => $validation_results ) );
1722
1723
		// We'll need this result when rendering the form ( on GFFormDisplay::get_form )
1724
		$this->form_after_validation = $validation_results['form'];
1725
1726
		return $validation_results;
1727
	}
1728
1729
1730
	/**
1731
	 * TODO: This seems to be hacky... we should remove it. Entry is set when updating the form using setup_vars()!
1732
	 * Get the current entry and set it if it's not yet set.
1733 19
	 * @return array Gravity Forms entry array
1734
	 */
1735
	public function get_entry() {
1736 19
1737 19
		if( empty( $this->entry ) ) {
1738 19
			// Get the database value of the entry that's being edited
1739
			$this->entry = gravityview_get_entry( GravityView_frontend::is_single_entry() );
1740
		}
1741
1742
		return $this->entry;
1743
	}
1744 19
1745
1746
1747 19
	// --- Filters
1748
1749
	/**
1750 19
	 * Get the Edit Entry fields as configured in the View
1751
	 *
1752
	 * @since 1.8
1753
	 *
1754
	 * @param int $view_id
1755
	 *
1756
	 * @return array Array of fields that are configured in the Edit tab in the Admin
1757
	 */
1758
	private function get_configured_edit_fields( $form, $view_id ) {
1759
1760 19
		// Get all fields for form
1761
		if ( \GV\View::exists( $view_id ) ) {
1762 19
			$view = \GV\View::by_id( $view_id );
1763
			$properties = $view->fields ? $view->fields->as_configuration() : array();
1764
		} else {
1765
			$properties = null;
1766
		}
1767
1768
		// If edit tab not yet configured, show all fields
1769
		$edit_fields = !empty( $properties['edit_edit-fields'] ) ? $properties['edit_edit-fields'] : NULL;
1770
1771
		// Hide fields depending on admin settings
1772
		$fields = $this->filter_fields( $form['fields'], $edit_fields );
1773
1774
	    // If Edit Entry fields are configured, remove adminOnly field settings. Otherwise, don't.
1775
	    $fields = $this->filter_admin_only_fields( $fields, $edit_fields, $form, $view_id );
1776
1777
		/**
1778 18
		 * @filter `gravityview/edit_entry/form_fields` Modify the fields displayed in Edit Entry form
1779
		 * @since 1.17
1780 18
		 * @param GF_Field[] $fields Gravity Forms form fields
1781
		 * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1782
		 * @param array $form GF Form array (`fields` key modified to have only fields configured to show in Edit Entry)
1783
		 * @param int $view_id View ID
1784 18
		 */
1785
		$fields = apply_filters( 'gravityview/edit_entry/form_fields', $fields, $edit_fields, $form, $view_id );
1786 18
1787
		return $fields;
1788 18
	}
1789
1790
1791
	/**
1792
	 * Filter area fields based on specified conditions
1793 18
	 *  - This filter removes the fields that have calculation configured
1794
	 *  - Hides fields that are hidden, etc.
1795
	 *
1796
	 * @uses GravityView_Edit_Entry::user_can_edit_field() Check caps
1797 18
	 * @access private
1798 5
	 * @param GF_Field[] $fields
1799
	 * @param array $configured_fields
1800
	 * @since  1.5
1801
	 * @return array $fields
1802 18
	 */
1803 3
	private function filter_fields( $fields, $configured_fields ) {
1804
1805
		if( empty( $fields ) || !is_array( $fields ) ) {
1806
			return $fields;
1807
		}
1808
1809 18
		$edit_fields = array();
1810 15
1811 15
		$field_type_blacklist = $this->loader->get_field_blacklist( $this->entry );
1812 15
1813 3
		if ( empty( $configured_fields ) && apply_filters( 'gravityview/features/paged-edit', false ) ) {
1814
			$field_type_blacklist = array_diff( $field_type_blacklist, array( 'page' ) );
1815
		}
1816 15
1817 2
		// First, remove blacklist or calculation fields
1818
		foreach ( $fields as $key => $field ) {
1819
1820 13
			// Remove the fields that have calculation properties and keep them to be used later
1821
			// @since 1.16.2
1822
			if( $field->has_calculation() ) {
1823 15
				$this->fields_with_calculation[] = $field;
1824
				// don't remove the calculation fields on form render.
1825
			}
1826
1827 5
			if( in_array( $field->type, $field_type_blacklist ) ) {
1828
				unset( $fields[ $key ] );
1829
			}
1830 5
		}
1831 5
1832 5
		// The Edit tab has not been configured, so we return all fields by default.
1833 5
		// But we do keep the hidden ones hidden please, for everyone :)
1834
		if ( empty( $configured_fields ) ) {
1835
			$out_fields = array();
1836
			foreach ( $fields as &$field ) {
1837
				if ( 'hidden' === $field->type ) {
1838
					continue; // A hidden field is just hidden
1839
				}
1840 5
1841
				if ( 'hidden' == $field->visibility ) {
1842
					continue; // Same
1843
				}
1844
1845
				$out_fields[] = $field;
1846
			}
1847
1848
			return array_values( $out_fields );
1849
		}
1850
1851 5
		// The edit tab has been configured, so we loop through to configured settings
1852
		foreach ( $configured_fields as $configured_field ) {
1853 5
1854
	        /** @var GF_Field $field */
1855 5
	        foreach ( $fields as $field ) {
1856
				if( intval( $configured_field['id'] ) === intval( $field->id ) && $this->user_can_edit_field( $configured_field, false ) ) {
1857 5
				    $edit_fields[] = $this->merge_field_properties( $field, $configured_field );
1858
				    break;
1859
				}
1860
1861 5
			}
1862
1863
		}
1864
1865
		return $edit_fields;
1866
1867
	}
1868
1869 5
	/**
1870
	 * Override GF Form field properties with the ones defined on the View
1871 5
	 * @param  GF_Field $field GF Form field object
1872
	 * @param  array $field_setting  GV field options
1873
	 * @since  1.5
1874
	 * @return array|GF_Field
1875
	 */
1876
	private function merge_field_properties( $field, $field_setting ) {
1877
1878
		$return_field = $field;
1879
1880
		if( empty( $field_setting['show_label'] ) ) {
1881
			$return_field->label = '';
1882
		} elseif ( !empty( $field_setting['custom_label'] ) ) {
1883
			$return_field->label = $field_setting['custom_label'];
1884
		}
1885
1886
		if( !empty( $field_setting['custom_class'] ) ) {
1887 18
			$return_field->cssClass .= ' '. gravityview_sanitize_html_class( $field_setting['custom_class'] );
1888
		}
1889
1890
		/**
1891
		 * Normalize page numbers - avoid conflicts with page validation
1892
		 * @since 1.6
1893
		 */
1894
		$return_field->pageNumber = 1;
1895
1896
		return $return_field;
1897
1898 18
	}
1899
1900 18
	/**
1901 1
	 * Remove fields that shouldn't be visible based on the Gravity Forms adminOnly field property
1902
	 *
1903
	 * @since 1.9.1
1904
	 *
1905
	 * @param array|GF_Field[] $fields Gravity Forms form fields
1906 1
	 * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1907
	 * @param array $form GF Form array
1908
	 * @param int $view_id View ID
1909 18
	 *
1910 18
	 * @return array Possibly modified form array
1911
	 */
1912
	private function filter_admin_only_fields( $fields = array(), $edit_fields = null, $form = array(), $view_id = 0 ) {
1913 18
1914
	    /**
1915
		 * @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
1916
	     * If the Edit Entry tab is not configured, adminOnly fields will not be shown to non-administrators.
1917
	     * If the Edit Entry tab *is* configured, adminOnly fields will be shown to non-administrators, using the configured GV permissions
1918
	     * @since 1.9.1
1919
	     * @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.
1920
	     * @param array $form GF Form array
1921
	     * @param int $view_id View ID
1922
	     */
1923
	    $use_gf_adminonly_setting = apply_filters( 'gravityview/edit_entry/use_gf_admin_only_setting', empty( $edit_fields ), $form, $view_id );
1924
1925
	    if( $use_gf_adminonly_setting && false === GVCommon::has_cap( 'gravityforms_edit_entries', $this->entry['id'] ) ) {
1926
			foreach( $fields as $k => $field ) {
1927
				if( $field->adminOnly ) {
1928 18
				    unset( $fields[ $k ] );
1929
				}
1930 18
			}
1931
			return array_values( $fields );
1932 18
		}
1933 18
1934
	    foreach( $fields as &$field ) {
1935
		    $field->adminOnly = false;
1936 2
		}
1937 2
1938 1
		return $fields;
1939
	}
1940
1941
	/**
1942
	 * Checkboxes and other checkbox-based controls should not
1943 18
	 * display default checks in edit mode.
1944
	 *
1945
	 * https://github.com/gravityview/GravityView/1149
1946
	 *
1947
	 * @since 2.1
1948
	 *
1949
	 * @param array $form Gravity Forms array object
1950
	 *
1951
	 * @return array $form, modified to default checkboxes, radios from showing up.
1952
	 */
1953
	private function unselect_default_values( $form ) {
1954
1955
	    foreach ( $form['fields'] as &$field ) {
1956
1957
			if ( empty( $field->choices ) ) {
1958
                continue;
1959
			}
1960
1961 18
            foreach ( $field->choices as &$choice ) {
1962
				if ( \GV\Utils::get( $choice, 'isSelected' ) ) {
1963 18
					$choice['isSelected'] = false;
1964 16
				}
1965
			}
1966
		}
1967
1968
		return $form;
1969 2
	}
1970
1971 2
	// --- Conditional Logic
1972
1973
	/**
1974
	 * Conditional logic isn't designed to work with forms that already have content. When switching input values,
1975
	 * the dependent fields will be blank.
1976
	 *
1977
	 * Note: This is because GF populates a JavaScript variable with the input values. This is tough to filter at the input level;
1978
	 * via the `gform_field_value` filter; it requires lots of legwork. Doing it at the form level is easier.
1979
	 *
1980
	 * @since 1.17.4
1981
	 *
1982
	 * @param array $form Gravity Forms array object
1983
	 *
1984 2
	 * @return array $form, modified to fix conditional
1985
	 */
1986 2
	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...
1987
1988 2
		if( ! GFFormDisplay::has_conditional_logic( $form ) ) {
1989
			return $form;
1990
		}
1991
1992
		// Have Conditional Logic pre-fill fields as if the data were default values
1993
		/** @var GF_Field $field */
1994
		foreach ( $form['fields'] as &$field ) {
1995
1996
			if( 'checkbox' === $field->type ) {
1997
				foreach ( $field->get_entry_inputs() as $key => $input ) {
1998
				    $input_id = $input['id'];
1999
				    $choice = $field->choices[ $key ];
2000 2
				    $value = \GV\Utils::get( $this->entry, $input_id );
2001
				    $match = RGFormsModel::choice_value_match( $field, $choice, $value );
2002
				    if( $match ) {
2003
				        $field->choices[ $key ]['isSelected'] = true;
2004
				    }
2005
				}
2006
			} else {
2007 2
2008
				// We need to run through each field to set the default values
2009
				foreach ( $this->entry as $field_id => $field_value ) {
2010
2011
				    if( floatval( $field_id ) === floatval( $field->id ) ) {
2012
2013
				        if( 'list' === $field->type ) {
2014
				            $list_rows = maybe_unserialize( $field_value );
2015
2016
				            $list_field_value = array();
2017
				            foreach ( (array) $list_rows as $row ) {
2018
				                foreach ( (array) $row as $column ) {
2019 18
				                    $list_field_value[] = $column;
2020
				                }
2021
				            }
2022
2023
				            $field->defaultValue = serialize( $list_field_value );
2024
				        } else {
2025
				            $field->defaultValue = $field_value;
2026
				        }
2027 18
				    }
2028 18
				}
2029 18
			}
2030 18
		}
2031
2032 18
		return $form;
2033 18
	}
2034 18
2035 3
	/**
2036 3
	 * Remove the conditional logic rules from the form button and the form fields, if needed.
2037
	 *
2038
	 * @todo Merge with caller method
2039
	 * @since 1.9
2040
	 *
2041 2
	 * @param array $form Gravity Forms form
2042 2
	 * @return array Modified form, if not using Conditional Logic
2043
	 */
2044
	private function filter_conditional_logic( $form ) {
2045
		/**
2046
		 * Fields that are tied to a conditional logic field that is not present in the view
2047
		 * have to still be displayed, if the condition is met.
2048
		 *
2049 2
		 * @see https://github.com/gravityview/GravityView/issues/840
2050
		 * @since develop
2051 2
		 */
2052 2
		$the_form = GFAPI::get_form( $form['id'] );
2053
		$editable_ids = array();
2054
		foreach ( $form['fields'] as $field ) {
2055
			$editable_ids[] = $field['id']; // wp_list_pluck is destructive in this context
2056
		}
2057
		$remove_conditions_rule = array();
2058
		foreach ( $the_form['fields'] as $field ) {
2059 18
			if ( ! empty( $field->conditionalLogic ) && ! empty( $field->conditionalLogic['rules'] ) ) {
2060 2
				foreach ( $field->conditionalLogic['rules'] as $i => $rule ) {
2061 2
					if ( ! in_array( $rule['fieldId'], $editable_ids ) ) {
2062
						/**
2063 2
						 * This conditional field is not editable in this View.
2064
						 * We need to remove the rule, but only if it matches.
2065 2
						 */
2066 1
						if ( $_field = GFAPI::get_field( $the_form, $rule['fieldId'] ) ) {
2067 1
							$value = $_field->get_value_export( $this->entry );
2068
						} elseif ( isset( $this->entry[ $rule['fieldId'] ] ) ) {
2069
							$value = $this->entry[ $rule['fieldId'] ];
2070
						} else {
2071
							$value = gform_get_meta( $this->entry['id'], $rule['fieldId'] );
2072
						}
2073
2074 18
						$match = GFFormsModel::matches_operation( $value, $rule['value'], $rule['operator'] );
2075
						
2076
						if ( $match ) {
2077
							$remove_conditions_rule[] = array( $field['id'], $i );
2078
						}
2079
					}
2080
				}
2081
			}
2082 18
		}
2083
2084 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...
2085 18
			foreach ( $form['fields'] as &$field ) {
2086
				foreach ( $remove_conditions_rule as $_remove_conditions_r ) {
2087
2088
				    list( $rule_field_id, $rule_i ) = $_remove_conditions_r;
2089
2090
					if ( $field['id'] == $rule_field_id ) {
2091
						unset( $field->conditionalLogic['rules'][ $rule_i ] );
2092
						gravityview()->log->debug( 'Removed conditional rule #{rule} for field {field_id}', array( 'rule' => $rule_i, 'field_id' => $field['id'] ) );
2093
					}
2094
				}
2095
			}
2096
		}
2097
2098
		/** Normalize the indices... */
2099
		$form['fields'] = array_values( $form['fields'] );
2100
2101
		/**
2102
		 * @filter `gravityview/edit_entry/conditional_logic` Should the Edit Entry form use Gravity Forms conditional logic showing/hiding of fields?
2103
		 * @since 1.9
2104
		 * @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
2105
		 * @param array $form Gravity Forms form
2106
		 */
2107
		$use_conditional_logic = apply_filters( 'gravityview/edit_entry/conditional_logic', true, $form );
2108 18
2109
		if( $use_conditional_logic ) {
2110 18
			return $form;
2111
		}
2112
2113
		foreach( $form['fields'] as &$field ) {
2114
			/* @var GF_Field $field */
2115 18
			$field->conditionalLogic = null;
2116
		}
2117
2118
		unset( $form['button']['conditionalLogic'] );
2119
2120
		return $form;
2121
2122
	}
2123
2124
	/**
2125
	 * Disable the Gravity Forms conditional logic script and features on the Edit Entry screen
2126
	 *
2127
	 * @since 1.9
2128
	 *
2129
	 * @param $has_conditional_logic
2130
	 * @param $form
2131
	 * @return mixed
2132
	 */
2133 19
	public function manage_conditional_logic( $has_conditional_logic, $form ) {
2134
2135 19
		if( ! $this->is_edit_entry() ) {
2136
			return $has_conditional_logic;
2137
		}
2138
2139
	    /** @see GravityView_Edit_Entry_Render::filter_conditional_logic for filter documentation */
2140
		return apply_filters( 'gravityview/edit_entry/conditional_logic', $has_conditional_logic, $form );
2141
	}
2142 19
2143
2144
	// --- User checks and nonces
2145
2146
	/**
2147
	 * Check if the user can edit the entry
2148 19
	 *
2149
	 * - Is the nonce valid?
2150
	 * - Does the user have the right caps for the entry
2151
	 * - Is the entry in the trash?
2152 19
	 *
2153
	 * @todo Move to GVCommon
2154
	 *
2155
	 * @param  boolean $echo Show error messages in the form?
2156
	 * @return boolean        True: can edit form. False: nope.
2157
	 */
2158
	private function user_can_edit_entry( $echo = false ) {
2159
2160
		$error = NULL;
2161
2162
		/**
2163
		 *  1. Permalinks are turned off
2164
		 *  2. There are two entries embedded using oEmbed
2165
		 *  3. One of the entries has just been saved
2166 19
		 */
2167 2
		if( !empty( $_POST['lid'] ) && !empty( $_GET['entry'] ) && ( $_POST['lid'] !== $_GET['entry'] ) ) {
2168
2169
			$error = true;
2170 19
2171
		}
2172
2173
		if( !empty( $_GET['entry'] ) && (string)$this->entry['id'] !== $_GET['entry'] ) {
2174
2175 19
			$error = true;
2176 19
2177
		} elseif( ! $this->verify_nonce() ) {
2178
2179 2
			/**
2180
			 * If the Entry is embedded, there may be two entries on the same page.
2181 2
			 * If that's the case, and one is being edited, the other should fail gracefully and not display an error.
2182
			 */
2183
			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...
2184
				$error = true;
2185
			} else {
2186 2
				$error = __( 'The link to edit this entry is not valid; it may have expired.', 'gravityview');
2187 2
			}
2188
2189
		}
2190 2
2191
		if( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $this->entry ) ) {
2192
			$error = __( 'You do not have permission to edit this entry.', 'gravityview');
2193 2
		}
2194
2195 2
		if( $this->entry['status'] === 'trash' ) {
2196
			$error = __('You cannot edit the entry; it is in the trash.', 'gravityview' );
2197
		}
2198
2199
		// No errors; everything's fine here!
2200
		if( empty( $error ) ) {
2201
			return true;
2202
		}
2203
2204
		if( $echo && $error !== true ) {
2205
2206 5
	        $error = esc_html( $error );
2207
2208 5
	        /**
2209
	         * @since 1.9
2210 5
	         */
2211 1
	        if ( ! empty( $this->entry ) ) {
2212
		        $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;" ) );
2213
	        }
2214
2215 5
			echo GVCommon::generate_notice( wpautop( $error ), 'gv-error error');
2216 5
		}
2217
2218
		gravityview()->log->error( '{error}', array( 'error' => $error ) );
2219 1
2220
		return false;
2221
	}
2222
2223 1
2224
	/**
2225 1
	 * Check whether a field is editable by the current user, and optionally display an error message
2226
	 * @uses  GravityView_Edit_Entry->check_user_cap_edit_field() Check user capabilities
2227
	 * @param  array  $field Field or field settings array
2228
	 * @param  boolean $echo  Whether to show error message telling user they aren't allowed
2229
	 * @return boolean         True: user can edit the current field; False: nope, they can't.
2230
	 */
2231
	private function user_can_edit_field( $field, $echo = false ) {
2232
2233
		$error = NULL;
2234
2235
		if( ! $this->check_user_cap_edit_field( $field ) ) {
2236
			$error = __( 'You do not have permission to edit this field.', 'gravityview');
2237
		}
2238 5
2239
		// No errors; everything's fine here!
2240
		if( empty( $error ) ) {
2241 5
			return true;
2242 4
		}
2243
2244
		if( $echo ) {
2245 1
			echo GVCommon::generate_notice( wpautop( esc_html( $error ) ), 'gv-error error');
2246
		}
2247 1
2248 1
		gravityview()->log->error( '{error}', array( 'error' => $error ) );
2249
2250
		return false;
2251
2252
	}
2253
2254
2255
	/**
2256
	 * checks if user has permissions to edit a specific field
2257
	 *
2258
	 * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_field for maximum security!!
2259 18
	 *
2260
	 * @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...
2261
	 * @return bool
2262 18
	 */
2263
	private function check_user_cap_edit_field( $field ) {
2264
2265
		// If they can edit any entries (as defined in Gravity Forms), we're good.
2266
		if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ) ) ) {
2267 18
			return true;
2268
		}
2269
2270
		$field_cap = isset( $field['allow_edit_cap'] ) ? $field['allow_edit_cap'] : false;
2271
2272 18
		if( $field_cap ) {
2273
			return GVCommon::has_cap( $field['allow_edit_cap'] );
2274
		}
2275
2276
		return false;
2277
	}
2278
2279
2280
	/**
2281 18
	 * Is the current nonce valid for editing the entry?
2282
	 * @return boolean
2283 18
	 */
2284
	public function verify_nonce() {
2285
2286
		// Verify form submitted for editing single
2287
		if( $this->is_edit_entry_submission() ) {
2288
			$valid = wp_verify_nonce( $_POST[ self::$nonce_field ], self::$nonce_field );
2289
		}
2290
2291
		// Verify
2292
		else if( ! $this->is_edit_entry() ) {
2293
			$valid = false;
2294
		}
2295
2296
		else {
2297
			$valid = wp_verify_nonce( $_GET['edit'], self::$nonce_key );
2298
		}
2299
2300
		/**
2301
		 * @filter `gravityview/edit_entry/verify_nonce` Override Edit Entry nonce validation. Return true to declare nonce valid.
2302
		 * @since 1.13
2303
		 * @param int|boolean $valid False if invalid; 1 or 2 when nonce was generated
2304
		 * @param string $nonce_field Key used when validating submissions. Default: is_gv_edit_entry
2305
		 */
2306
		$valid = apply_filters( 'gravityview/edit_entry/verify_nonce', $valid, self::$nonce_field );
2307
2308
		return $valid;
2309
	}
2310
2311
2312
	/**
2313
	 * Multiselect in GF 2.2 became a json_encoded value. Fix it.
2314
	 *
2315
	 * As a hack for now we'll implode it back.
2316
	 */
2317
	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...
2318
		if ( empty ( $field->storageType ) || $field->storageType != 'json' ) {
2319
			return $field_value;
2320
		}
2321
2322
		$maybe_json = @json_decode( $field_value, true );
2323
2324
		if ( $maybe_json ) {
2325
			return implode( ',', $maybe_json );
2326
		}
2327
2328
		return $field_value;
2329
	}
2330
2331
2332
2333
} //end class
2334