Completed
Push — develop ( 1b9b3e...5c91dc )
by Zack
04:18
created

GravityView_Entry_Approval::update_bulk()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 11
nc 6
nop 3
dl 0
loc 21
rs 7.551
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 15.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @file class-gravityview-entry-approval.php
4
 * @package   GravityView
5
 * @license   GPL2+
6
 * @author    Katz Web Services, Inc.
7
 * @link      https://gravityview.co
8
 * @copyright Copyright 2016, Katz Web Services, Inc.
9
 *
10
 * @since 1.18
11
 */
12
13
/** If this file is called directly, abort. */
14
if ( ! defined( 'ABSPATH' ) ) {
15
	die;
16
}
17
18
/**
19
 * Generate linked list output for a list of entries.
20
 *
21
 * @since 1.18
22
 */
23
class GravityView_Entry_Approval {
24
25
	/**
26
	 * @var string Key used to store approval status in the Gravity Forms entry meta table
27
	 */
28
	const meta_key = 'is_approved';
29
30
	public function __construct() {
31
		$this->add_hooks();
32
	}
33
34
	/**
35
	 * Add actions and filters related to entry approval
36
	 *
37
	 * @return void
38
	 */
39
	private function add_hooks() {
40
41
		// in case entry is edited (on admin or frontend)
42
		add_action( 'gform_after_update_entry', array( $this, 'after_update_entry_update_approved_meta' ), 10, 2);
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
43
44
		// when using the User opt-in field, check on entry submission
45
		add_action( 'gform_after_submission', array( $this, 'after_submission' ), 10, 2 );
46
47
		// process ajax approve entry requests
48
		add_action('wp_ajax_gv_update_approved', array( $this, 'ajax_update_approved'));
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
No space before closing parenthesis of array is bad style
Loading history...
49
50
	}
51
52
	/**
53
	 * Approve/Disapprove entries using the × or ✓ icons in the GF Entries screen
54
	 *
55
	 * @uses wp_send_json_error()
56
	 * @uses wp_send_json_success()
57
	 *
58
	 * Expects a $_POST request with the following $_POST keys and values:
59
	 *
60
	 * @global array $_POST {
61
	 * @type int $form_id ID of the form connected to the entry being updated
62
	 * @type string|int $entry_slug The ID or slug of the entry being updated
63
	 * @type string $approved The value of the entry approval status {@see GravityView_Entry_Approval_Status::is_valid() }
64
	 * }
65
	 *
66
	 * @return void Prints result using wp_send_json_success() and wp_send_json_error()
67
	 */
68
	public function ajax_update_approved() {
69
70
		$form_id = intval( rgpost('form_id') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
71
72
		$entry_id = GVCommon::get_entry_id( rgpost('entry_slug') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
73
74
		$approval_status = rgpost('approved');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
75
76
		$nonce = rgpost('nonce');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
77
78
		// Valid status
79
		if( ! GravityView_Entry_Approval_Status::is_valid( $approval_status ) ) {
80
81
			do_action( 'gravityview_log_error', __METHOD__ . ': Invalid approval status', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
82
83
			$result = new WP_Error( 'invalid_status', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
84
85
		}
86
87
		// Valid values
88
		elseif ( empty( $entry_id ) || empty( $form_id ) ) {
89
90
			do_action( 'gravityview_log_error', __METHOD__ . ' entry_id or form_id are empty.', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
91
92
			$result = new WP_Error( 'empty_details', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
93
94
		}
95
96
		// Valid nonce
97
		else if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'gravityview_entry_approval' ) ) {
98
99
			do_action( 'gravityview_log_error', __METHOD__ . ' Security check failed.', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
100
101
			$result = new WP_Error( 'invalid_nonce', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
102
103
		}
104
105
		// Has capability
106
		elseif ( ! GVCommon::has_cap( 'gravityview_moderate_entries', $entry_id ) ) {
107
108
			do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
109
110
			$result = new WP_Error( 'Missing Cap: gravityview_moderate_entries', __( 'You do not have permission to edit this entry.', 'gravityview') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
111
112
		}
113
114
		// All checks passed
115
		else {
116
117
			$result = self::update_approved( $entry_id, $approval_status, $form_id );
118
119
		}
120
121
		if ( is_wp_error( $result ) ) {
122
			do_action( 'gravityview_log_error', __METHOD__ . ' Error updating approval: ' . $result->get_error_message() );
123
124
			wp_send_json_error( $result );
125
		}
126
127
		wp_send_json_success();
128
	}
129
130
	/**
131
	 * Update the is_approved meta whenever the entry is submitted (and it contains a User Opt-in field)
132
	 *
133
	 * @since 1.16.6
134
	 *
135
	 * @param $entry array Gravity Forms entry object
136
	 * @param $form array Gravity Forms form object
137
	 */
138
	public function after_submission( $entry, $form ) {
139
		$this->after_update_entry_update_approved_meta( $form , $entry['id'] );
140
	}
141
142
	/**
143
	 * Update the is_approved meta whenever the entry is updated
144
	 *
145
	 * @since 1.7.6.1 Was previously named `update_approved_meta`
146
	 *
147
	 * @param  array $form     Gravity Forms form array
148
	 * @param  int $entry_id ID of the Gravity Forms entry
149
	 * @return void
150
	 */
151
	public function after_update_entry_update_approved_meta( $form, $entry_id = NULL ) {
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
152
153
		$approved_column = self::get_approved_column( $form['id'] );
154
155
		/**
156
		 * If the form doesn't contain the approve field, don't assume anything.
157
		 */
158
		if( empty( $approved_column ) ) {
159
			return;
160
		}
161
162
		$entry = GFAPI::get_entry( $entry_id );
163
164
		self::update_approved_meta( $entry_id, $entry[ (string)$approved_column ], $form['id'] );
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
165
	}
166
167
	/**
168
	 * Process a bulk of entries to update the approve field/property
169
	 *
170
	 * @since 1.18 Moved to GravityView_Entry_Approval
171
	 * @since 1.18 Made public
172
	 *
173
	 * @access public
174
	 * @static
175
	 * @param array|boolean $entries If array, array of entry IDs that are to be updated. If true: update all entries.
176
	 * @param int $approved Approved status. If `0`: unapproved, if not empty, `Approved`
177
	 * @param int $form_id The Gravity Forms Form ID
178
	 * @return boolean|void
179
	 */
180
	public static function update_bulk( $entries = array(), $approved, $form_id ) {
181
182
		if( empty($entries) || ( $entries !== true && !is_array($entries) ) ) {
0 ignored issues
show
introduced by
Found "!== true". Use Yoda Condition checks, you must
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
Expected 1 space after "!"; 0 found
Loading history...
183
			do_action( 'gravityview_log_error', __METHOD__ . ' Entries were empty or malformed.', $entries );
184
			return false;
185
		}
186
187
		if( ! GVCommon::has_cap( 'gravityview_moderate_entries' ) ) {
188
			do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
189
			return false;
190
		}
191
192
		$status = GravityView_Entry_Approval_Status::is_disapproved( $approved ) ? GravityView_Entry_Approval_Status::Disapproved : GravityView_Entry_Approval_Status::Approved;
193
194
		// calculate approved field id once instead of looping through in the update_approved() method
195
		$approved_column_id = self::get_approved_column( $form_id );
196
197
		foreach( $entries as $entry_id ) {
0 ignored issues
show
Bug introduced by
The expression $entries of type boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
198
			self::update_approved( (int)$entry_id, $status, $form_id, $approved_column_id );
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
199
		}
200
	}
201
202
	/**
203
	 * update_approved function.
204
	 *
205
	 * @since 1.18 Moved to GravityView_Entry_Approval class
206
	 *
207
	 * @access public
208
	 * @static
209
	 * @param int $entry_id (default: 0)
210
	 * @param int $approved (default: 0)
211
	 * @param int $form_id (default: 0)
212
	 * @param int $approvedcolumn (default: 0)
213
	 *
214
	 * @return boolean True: It worked; False: it failed
215
	 */
216
	public static function update_approved( $entry_id = 0, $approved = 0, $form_id = 0, $approvedcolumn = 0 ) {
217
218
		if( !class_exists( 'GFAPI' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
219
			do_action( 'gravityview_log_error', __METHOD__ . 'GFAPI does not exist' );
220
			return false;
221
		}
222
223
		if( ! GravityView_Entry_Approval_Status::is_valid( $approved ) ) {
224
			do_action( 'gravityview_log_error', __METHOD__ . ': Not a valid approval value.' );
225
			return false;
226
		}
227
228
		$result = self::update_approved_column( $entry_id, $approved, $form_id, $approvedcolumn );
229
230
		/**
231
		 * GFAPI::update_entry() doesn't trigger `gform_after_update_entry`, so we trigger updating the meta ourselves.
232
		 */
233
		self::update_approved_meta( $entry_id, $approved, $form_id );
234
235
		// add note to entry if approval field updating worked or there was no approved field
236
		// There's no validation for the meta
237
		if( true === $result ) {
238
239
			$note = empty( $approved ) ? __( 'Disapproved the Entry for GravityView', 'gravityview' ) : __( 'Approved the Entry for GravityView', 'gravityview' );
240
241
			/**
242
			 * @filter `gravityview/approve_entries/add-note` Add a note when the entry has been approved or disapproved?
243
			 * @since 1.16.3
244
			 * @param bool $add_note True: Yep, add that note! False: Do not, under any circumstances, add that note!
245
			 */
246
			$add_note = apply_filters( 'gravityview/approve_entries/add-note', true );
247
248
			if( $add_note && class_exists( 'GravityView_Entry_Notes' ) ) {
249
				$current_user = wp_get_current_user();
250
				GravityView_Entry_Notes::add_note( $entry_id, $current_user->ID, $current_user->display_name, $note );
251
			}
252
253
			/**
254
			 * Destroy the cache for this form
255
			 * @see class-cache.php
256
			 * @since 1.5.1
257
			 */
258
			do_action( 'gravityview_clear_form_cache', $form_id );
259
260
		} else if( is_wp_error( $result ) ) {
261
262
			do_action( 'gravityview_log_error', __METHOD__ . sprintf( ' - Entry approval not updated: %s', $result->get_error_message() ) );
263
264
			$result = false;
265
		}
266
267
		return $result;
268
	}
269
270
	/**
271
	 * Update the Approve/Disapproved field value
272
	 *
273
	 * @param  int $entry_id ID of the Gravity Forms entry
274
	 * @param  string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
275
	 * @param int $form_id ID of the form of the entry being updated. Improves query performance.
276
	 * @param string $approvedcolumn Gravity Forms Field ID
277
	 *
278
	 * @return true|WP_Error
279
	 */
280
	private static function update_approved_column( $entry_id = 0, $status = '0', $form_id = 0, $approvedcolumn = 0 ) {
281
282
		if( empty( $approvedcolumn ) ) {
283
			$approvedcolumn = self::get_approved_column( $form_id );
284
		}
285
286
		if ( empty( $approvedcolumn ) ) {
287
			return true;
288
		}
289
290
		if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
291
			return new WP_Error( 'invalid_status', 'Invalid entry approval status', $status );
292
		}
293
294
		//get the entry
295
		$entry = GFAPI::get_entry( $entry_id );
296
297
		//update entry
298
		$entry[ (string)$approvedcolumn ] = $status;
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
299
300
		/** @var bool|WP_Error $result */
301
		$result = GFAPI::update_entry( $entry );
302
303
		return $result;
304
	}
305
306
	/**
307
	 * Update the `is_approved` entry meta value
308
	 *
309
	 * @since 1.7.6.1 `after_update_entry_update_approved_meta` was previously to be named `update_approved_meta`
310
	 * @since 1.17.1 Added $form_id parameter
311
	 *
312
	 * @param  int $entry_id ID of the Gravity Forms entry
313
	 * @param  string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
314
	 * @param int $form_id ID of the form of the entry being updated. Improves query performance.
315
	 *
316
	 * @return void
317
	 */
318
	private static function update_approved_meta( $entry_id, $status, $form_id = 0 ) {
319
320
		if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
321
			do_action('gravityview_log_error', __METHOD__ . ': $is_approved not valid value', $status );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
322
			return;
323
		}
324
325
		/**
326
		 * Make sure that the "User Opt-in" and the Admin Approve/Reject entry set the same meta value
327
		 * @since 1.16.6
328
		 */
329
		$is_approved = GravityView_Entry_Approval_Status::is_approved( $status );
330
331
		$approval_status = $is_approved ? GravityView_Entry_Approval_Status::Approved : GravityView_Entry_Approval_Status::Disapproved;
332
333
		// update entry meta
334
		if( function_exists('gform_update_meta') ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
335
336
			gform_update_meta( $entry_id, self::meta_key, $approval_status, $form_id );
337
338
			/**
339
			 * @action `gravityview/approve_entries/updated` Triggered when an entry approval is updated
340
			 * @since 1.7.6.1
341
			 * @param  int $entry_id ID of the Gravity Forms entry
342
			 * @param  string|int $approval_status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
343
			 */
344
			do_action( 'gravityview/approve_entries/updated', $entry_id, $approval_status );
345
346
			if( ! $is_approved ) {
347
348
				/**
349
				 * @action `gravityview/approve_entries/disapproved` Triggered when an entry is rejected
350
				 * @since 1.7.6.1
351
				 * @param  int $entry_id ID of the Gravity Forms entry
352
				 */
353
				do_action( 'gravityview/approve_entries/disapproved', $entry_id );
354
355
			} else {
356
357
				/**
358
				 * @action `gravityview/approve_entries/approved` Triggered when an entry is approved
359
				 * @since 1.7.6.1
360
				 * @param  int $entry_id ID of the Gravity Forms entry
361
				 */
362
				do_action( 'gravityview/approve_entries/approved', $entry_id );
363
364
			}
365
366
		} else {
367
368
			do_action('gravityview_log_error', __METHOD__ . ' - `gform_update_meta` does not exist.' );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
369
370
		}
371
	}
372
373
	/**
374
	 * Calculate the approve field.input id
375
	 *
376
	 * @access public
377
	 * @static
378
	 * @param mixed $form GF Form or Form ID
379
	 * @return false|null|string Returns the input ID of the approved field. Returns NULL if no approved fields were found. Returns false if $form_id wasn't set.
380
	 */
381
	static public function get_approved_column( $form ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
382
383
		if( empty( $form ) ) {
384
			return null;
385
		}
386
387
		if( !is_array( $form ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
388
			$form = GVCommon::get_form( $form );
389
		}
390
391
		foreach( $form['fields'] as $key => $field ) {
392
393
			$field = (array) $field;
394
395
			if( !empty( $field['gravityview_approved'] ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
396
				if( !empty($field['inputs'][0]['id']) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
397
					return $field['inputs'][0]['id'];
398
				}
399
			}
400
401
			// Note: This is just for backward compatibility from GF Directory plugin and old GV versions - when using i18n it may not work..
402
			if( 'checkbox' == $field['type'] && isset( $field['inputs'] ) && is_array( $field['inputs'] ) ) {
403
				foreach ( $field['inputs'] as $key2 => $input ) {
404
					if ( strtolower( $input['label'] ) == 'approved' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
405
						return $input['id'];
406
					}
407
				}
408
			}
409
		}
410
411
		return null;
412
	}
413
414
}
415
416
new GravityView_Entry_Approval;