Completed
Push — develop ( d3c2ad...5bd886 )
by Zack
32:53 queued 30:32
created

GravityView_Edit_Entry_Render   F

Complexity

Total Complexity 322

Size/Duplication

Total Lines 2423
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 74.6%

Importance

Changes 0
Metric Value
dl 0
loc 2423
ccs 602
cts 807
cp 0.746
rs 0.8
c 0
b 0
f 0
wmc 322
lcom 1
cbo 11

47 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A load() 0 28 1
A prevent_render_form() 0 9 3
A prevent_maybe_process_form() 0 11 2
A is_edit_entry() 0 6 3
A is_edit_entry_submission() 0 3 1
A setup_vars() 0 18 1
A init() 0 32 5
A print_scripts() 0 12 1
B process_save() 0 94 6
B unset_hidden_field_values() 0 59 10
B preset_approval_fields() 0 29 7
A prevent_update_unapproved_meta() 0 13 2
A process_save_process_files() 0 16 2
B save_field_value() 0 23 6
A modify_fileupload_settings() 0 9 2
B form_prepare_for_save() 0 29 6
C update_calculation_fields() 0 64 14
C update_post_image() 0 73 14
F maybe_update_post_fields() 0 115 22
A fill_post_template() 0 19 2
C after_update() 0 54 13
B edit_entry_form() 0 56 1
C maybe_print_message() 0 97 11
C render_edit_form() 0 101 9
A render_form_buttons() 0 3 1
A filter_modify_form_fields() 0 26 5
A verify_user_can_edit_post() 0 31 5
B modify_edit_field_input() 0 42 11
D get_field_value() 0 80 20
C gform_pre_validation() 0 87 14
A validate() 0 36 3
F custom_validation() 0 125 23
A get_entry() 0 9 2
A get_configured_edit_fields() 0 31 4
C filter_fields() 0 65 16
A merge_field_properties() 0 23 4
B filter_admin_only_fields() 0 28 6
A unselect_default_values() 0 17 5
B prefill_conditional_logic() 0 48 11
D filter_conditional_logic() 0 79 16
A manage_conditional_logic() 0 9 2
C user_can_edit_entry() 0 64 14
A user_can_edit_field() 0 22 4
A check_user_cap_edit_field() 0 15 4
A verify_nonce() 0 26 3
A fix_multiselect_value_serialization() 0 13 4

How to fix   Complexity   

Complex Class

Complex classes like GravityView_Edit_Entry_Render often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GravityView_Edit_Entry_Render, and based on these observations, apply Extract Interface, too.

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