Completed
Push — develop ( 31c9ca...168da6 )
by Zack
38:08 queued 17:59
created

GravityView_Edit_Entry::add_hooks()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 17
ccs 7
cts 7
cp 1
crap 1
rs 9.7
c 0
b 0
f 0
1
<?php
2
/**
3
 * The GravityView Edit Entry Extension
4
 *
5
 * Easily edit entries in GravityView.
6
 *
7
 * @package   GravityView
8
 * @license   GPL2+
9
 * @author    GravityView <[email protected]>
10
 * @link      http://gravityview.co
11
 * @copyright Copyright 2014, Katz Web Services, Inc.
12
 */
13
14
if ( ! defined( 'WPINC' ) ) {
15
	die;
16
}
17
18
19
class GravityView_Edit_Entry {
20
21
    /**
22
     * @var string
23
     */
24
	static $file;
25
26
	static $instance;
27
28
    /**
29
     * Component instances.
30
     * @var array
31
     */
32
    public $instances = array();
33
34
35 22
	function __construct() {
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...
36
37 22
        self::$file = plugin_dir_path( __FILE__ );
38
39 22
        if( is_admin() ) {
40
            $this->load_components( 'admin' );
41
        }
42
43 22
		$this->load_components( 'locking' );
44
45 22
        $this->load_components( 'render' );
46
47
        // If GF User Registration Add-on exists
48 22
        $this->load_components( 'user-registration' );
49
50 22
        $this->add_hooks();
51
52
		// Process hooks for addons that may or may not be present
53 22
		$this->addon_specific_hooks();
54 22
	}
55
56
57 23
    static function getInstance() {
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...
58
59 23
        if( empty( self::$instance ) ) {
60 22
            self::$instance = new GravityView_Edit_Entry;
61
        }
62
63 23
        return self::$instance;
64
    }
65
66
67 22
    private function load_components( $component ) {
68
69 22
        $dir = trailingslashit( self::$file );
70
71 22
        $filename  = $dir . 'class-edit-entry-' . $component . '.php';
72 22
        $classname = 'GravityView_Edit_Entry_' . str_replace( ' ', '_', ucwords( str_replace( '-', ' ', $component ) ) );
73
74
        // Loads component and pass extension's instance so that component can
75
        // talk each other.
76 22
        require_once $filename;
77 22
        $this->instances[ $component ] = new $classname( $this );
78 22
        $this->instances[ $component ]->load();
79
80 22
    }
81
82 22
    private function add_hooks() {
83
84
        // Add front-end access to Gravity Forms delete file action
85 22
        add_action( 'wp_ajax_nopriv_rg_delete_file', array( 'GFForms', 'delete_file') );
86
87
        // Make sure this hook is run for non-admins
88 22
        add_action( 'wp_ajax_rg_delete_file', array( 'GFForms', 'delete_file') );
89
90 22
        add_filter( 'gravityview_blacklist_field_types', array( $this, 'modify_field_blacklist' ), 10, 2 );
91
92
        // add template path to check for field
93 22
        add_filter( 'gravityview_template_paths', array( $this, 'add_template_path' ) );
94
95 22
		add_filter( 'gravityview/field/is_visible', array( $this, 'maybe_not_visible' ), 10, 3 );
96
97 22
		add_filter( 'gravityview/api/reserved_query_args', array( $this, 'add_reserved_arg' ) );
98
    }
99
100
	/**
101
	 * Adds "edit" to the list of internal reserved query args
102
	 *
103 22
	 * @since 2.10
104
	 *
105 22
	 * @param array $args Existing reserved args
106
	 *
107
	 * @return array
108
	 */
109 22
	public function add_reserved_arg( $args ) {
110
111
		$args[] = 'edit';
112
113
		return $args;
114
	}
115
116
	/**
117
	 * Trigger hooks that are normally run in the admin for Addons, but need to be triggered manually because we're not in the admin
118
	 * @return void
119
	 */
120
	private function addon_specific_hooks() {
121
122
		if( class_exists( 'GFSignature' ) && is_callable( array( 'GFSignature', 'get_instance' ) ) ) {
123 44
			add_filter('gform_admin_pre_render', array( GFSignature::get_instance(), 'edit_lead_script'));
124
		}
125 44
126 44
	}
127
128
	/**
129
	 * Hide the field or not.
130
	 *
131
	 * For non-logged in users.
132
	 * For users that have no edit rights on any of the current entries.
133
	 *
134
	 * @param bool $visible Visible or not.
135
	 * @param \GV\Field $field The field.
136
	 * @param \GV\View $view The View context.
137
	 *
138
	 * @return bool
139
	 */
140
	public function maybe_not_visible( $visible, $field, $view ) {
141
142
		if ( 'edit_link' !== $field->ID ) {
143
			return $visible;
144
		}
145
146
		if ( ! $view instanceof \GV\View ) {
147
			return $visible;
148
		}
149
150
		static $visibility_cache_for_view = array();
151
152
		if ( ! is_null( $result = \GV\Utils::get( $visibility_cache_for_view, $view->ID, null ) ) ) {
153
			return $result;
154
		}
155
156 2
		foreach ( $view->get_entries()->all() as $entry ) {
157
			if ( self::check_user_cap_edit_entry( $entry->as_entry(), $view ) ) {
158
				// At least one entry is deletable for this user
159 2
				$visibility_cache_for_view[ $view->ID ] = true;
160
				return true;
161 2
			}
162
		}
163
164
		$visibility_cache_for_view[ $view->ID ] = false;
165
166
		return false;
167
	}
168
169
    /**
170
     * Include this extension templates path
171
     * @param array $file_paths List of template paths ordered
172
     */
173 24
    public function add_template_path( $file_paths ) {
174 24
175
        // Index 100 is the default GravityView template path.
176
        $file_paths[ 110 ] = self::$file;
177
178
        return $file_paths;
179
    }
180
181
    /**
182
     *
183
     * Return a well formatted nonce key according to GravityView Edit Entry protocol
184
     *
185
     * @param $view_id int GravityView view id
186
     * @param $form_id int Gravity Forms form id
187
     * @param $entry_id int Gravity Forms entry id
188
     * @return string
189
     */
190
    public static function get_nonce_key( $view_id, $form_id, $entry_id ) {
191 3
        return sprintf( 'edit_%d_%d_%d', $view_id, $form_id, $entry_id );
192
    }
193 3
194
195 3
    /**
196
     * The edit entry link creates a secure link with a nonce
197 3
     *
198 3
     * It also mimics the URL structure Gravity Forms expects to have so that
199 3
     * it formats the display of the edit form like it does in the backend, like
200
     * "You can edit this post from the post page" fields, for example.
201 3
     *
202 2
     * @param $entry array Gravity Forms entry object
203
     * @param $view_id int GravityView view id
204
     * @param $post_id int GravityView Post ID where View may be embedded {@since 1.9.2}
205
     * @param string|array $field_values Parameters to pass in to the Edit Entry form to prefill data. Uses the same format as Gravity Forms "Allow field to be populated dynamically" {@since 1.9.2} {@see https://www.gravityhelp.com/documentation/article/allow-field-to-be-populated-dynamically/ }
206
     * @return string
207
     */
208
    public static function get_edit_link( $entry, $view_id, $post_id = null, $field_values = '' ) {
209 3
210
        $nonce_key = self::get_nonce_key( $view_id, $entry['form_id'], $entry['id']  );
211
212
        $base = gv_entry_link( $entry, $post_id ? : $view_id  );
213
214
        $url = add_query_arg( array(
215
            'edit' => wp_create_nonce( $nonce_key )
216
        ), $base );
217
218
        if( $post_id ) {
219
	        $url = add_query_arg( array( 'gvid' => $view_id ), $url );
220
        }
221
222
	    /**
223
	     * Allow passing params to dynamically populate entry with values
224
	     * @since 1.9.2
225
	     */
226
	    if( !empty( $field_values ) ) {
227 3
228
		    if( is_array( $field_values ) ) {
229
			    // If already an array, no parse_str() needed
230
			    $params = $field_values;
231
		    } else {
232
			    parse_str( $field_values, $params );
233
		    }
234
235
		    $url = add_query_arg( $params, $url );
236
	    }
237
238
		/**
239
		 * @filter `gravityview/edit/link` Filter the edit URL link.
240
		 * @param[in,out] string $url The url.
241
		 * @param array $entry The entry.
242
		 * @param \GV\View $view The View.
243
		 */
244
		return apply_filters( 'gravityview/edit/link', $url, $entry, \GV\View::by_id( $view_id  ) );
245
    }
246
247
	/**
248
	 * Edit mode doesn't allow certain field types.
249
	 * @param  array $fields  Existing blacklist fields
250
	 * @param  string|null $context Context
251
	 * @return array          If not edit context, original field blacklist. Otherwise, blacklist including post fields.
252
	 */
253
	public function modify_field_blacklist( $fields = array(), $context = NULL ) {
254
255
		if( empty( $context ) || $context !== 'edit' ) {
256 22
			return $fields;
257
		}
258
259 22
		$add_fields = $this->get_field_blacklist();
260
261
		return array_merge( $fields, $add_fields );
262
	}
263
264
	/**
265
	 * Returns array of field types that should not be displayed in Edit Entry
266
	 *
267
	 * @since 1.20
268
	 *
269
	 * @param array $entry Gravity Forms entry array
270
	 *
271
	 * @return array Blacklist of field types
272
	 */
273
	function get_field_blacklist( $entry = array() ) {
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...
274
275
		$fields = array(
276
			'page',
277 22
			'payment_status',
278
			'payment_date',
279 22
			'payment_amount',
280
			'is_fulfilled',
281
			'transaction_id',
282
			'transaction_type',
283
			'captcha',
284
			'honeypot',
285
			'creditcard',
286
		);
287
288
		/**
289
		 * @filter `gravityview/edit_entry/field_blacklist` Array of fields that should not be displayed in Edit Entry
290
		 * @since 1.20
291
		 * @param array $fields Blacklist field type array
292 24
		 * @param array $entry Gravity Forms entry array
293
		 */
294
		$fields = apply_filters( 'gravityview/edit_entry/field_blacklist', $fields, $entry );
295 24
296
		return $fields;
297
	}
298 24
299
300 22
    /**
301 22
     * checks if user has permissions to edit a specific entry
302
     *
303 2
     * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_entry for maximum security!!
304
     *
305
     * @param  array $entry Gravity Forms entry array
306 2
     * @param \GV\View|int $view ID of the view you want to check visibility against {@since 1.9.2}. Required since 2.0
307
     * @return bool
308
     */
309
    public static function check_user_cap_edit_entry( $entry, $view = 0 ) {
310 2
311
        // No permission by default
312
        $user_can_edit = false;
313
314
		// get user_edit setting
315
		if ( empty( $view ) ) {
316 24
			// @deprecated path
317
			$view_id = GravityView_View::getInstance()->getViewId();
318 23
			$user_edit = GravityView_View::getInstance()->getAtts( 'user_edit' );
319
		} else {
320 23
			if ( $view instanceof \GV\View ) {
321
				$view_id = $view->ID;
322 3
			} else {
323
				$view_id = $view;
324 1
			}
325
326 1
			// in case is specified and not the current view
327
			$user_edit = GVCommon::get_template_setting( $view_id, 'user_edit' );
328
		}
329
330 3
        // If they can edit any entries (as defined in Gravity Forms)
331
        // Or if they can edit other people's entries
332
        // Then we're good.
333 3
        if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ), $entry['id'] ) ) {
334
335 2
            gravityview()->log->debug( 'User has ability to edit all entries.' );
336
337 2
            $user_can_edit = true;
338
339
        } else if( !isset( $entry['created_by'] ) ) {
340
341 2
            gravityview()->log->error( 'Entry `created_by` doesn\'t exist.');
342
343 2
            $user_can_edit = false;
344
345 2
        } else {
346
347 2
            $current_user = wp_get_current_user();
348
349
            // User edit is disabled
350
            if( empty( $user_edit ) ) {
351
352
                gravityview()->log->debug( 'User Edit is disabled. Returning false.' );
353
354
                $user_can_edit = false;
355
            }
356
357
            // User edit is enabled and the logged-in user is the same as the user who created the entry. We're good.
358
            else if( is_user_logged_in() && intval( $current_user->ID ) === intval( $entry['created_by'] ) ) {
359
360
                gravityview()->log->debug( 'User {user_id} created the entry.', array( 'user_id', $current_user->ID ) );
361
362
                $user_can_edit = true;
363 24
364
            } else if( ! is_user_logged_in() ) {
365 24
366
                gravityview()->log->debug( 'No user defined; edit entry requires logged in user' );
367
368
	            $user_can_edit = false; // Here just for clarity
369
            }
370
371
        }
372
373
        /**
374
         * @filter `gravityview/edit_entry/user_can_edit_entry` Modify whether user can edit an entry.
375
         * @since 1.15 Added `$entry` and `$view_id` parameters
376
         * @param[in,out] boolean $user_can_edit Can the current user edit the current entry? (Default: false)
377
         * @param[in] array $entry Gravity Forms entry array {@since 1.15}
378
         * @param[in] int $view_id ID of the view you want to check visibility against {@since 1.15}
379
         */
380
        $user_can_edit = apply_filters( 'gravityview/edit_entry/user_can_edit_entry', $user_can_edit, $entry, $view_id );
381
382
        return (bool) $user_can_edit;
383
    }
384
385
386
387
} // end class
388
389
//add_action( 'plugins_loaded', array('GravityView_Edit_Entry', 'getInstance'), 6 );
390
GravityView_Edit_Entry::getInstance();
391
392