Completed
Push — master ( 18187e...a1257b )
by Zack
19:22 queued 17:03
created

GravityView_Edit_Entry::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.004

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 20
ccs 9
cts 10
cp 0.9
crap 2.004
rs 9.6
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    Katz Web Services, Inc.
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
    }
98
99
	/**
100
	 * Trigger hooks that are normally run in the admin for Addons, but need to be triggered manually because we're not in the admin
101
	 * @return void
102
	 */
103 22
	private function addon_specific_hooks() {
104
105 22
		if( class_exists( 'GFSignature' ) && is_callable( array( 'GFSignature', 'get_instance' ) ) ) {
106
			add_filter('gform_admin_pre_render', array( GFSignature::get_instance(), 'edit_lead_script'));
107
		}
108
109 22
	}
110
111
	/**
112
	 * Hide the field or not.
113
	 *
114
	 * For non-logged in users.
115
	 * For users that have no edit rights on any of the current entries.
116
	 *
117
	 * @param bool $visible Visible or not.
118
	 * @param \GF\Field $field The field.
119
	 * @param \GV\View $view The View context.
120
	 *
121
	 * @return bool
122
	 */
123 44
	public function maybe_not_visible( $visible, $field, $view ) {
124 44
		if ( 'edit_link' !== $field->ID ) {
125 44
			return $visible;
126
		}
127
128
		if ( ! is_user_logged_in() ) {
129
			return false;
130
		}
131
132
		if ( ! $view ) {
133
			return $visible;
134
		}
135
136
		static $visiblity_cache_for_view = array();
137
138
		if ( ! is_null( $result = \GV\Utils::get( $visiblity_cache_for_view, $view->ID, null ) ) ) {
139
			return $result;
140
		}
141
142
		foreach ( $view->get_entries()->all() as $entry ) {
143
			if ( self::check_user_cap_edit_entry( $entry->as_entry(), $view ) ) {
144
				// At least one entry is deletable for this user
145
				$visiblity_cache_for_view[ $view->ID ] = true;
146
				return true;
147
			}
148
		}
149
150
		$visiblity_cache_for_view[ $view->ID ] = false;
151
152
		return false;
153
	}
154
155
    /**
156
     * Include this extension templates path
157
     * @param array $file_paths List of template paths ordered
158
     */
159 2
    public function add_template_path( $file_paths ) {
160
161
        // Index 100 is the default GravityView template path.
162 2
        $file_paths[ 110 ] = self::$file;
163
164 2
        return $file_paths;
165
    }
166
167
    /**
168
     *
169
     * Return a well formatted nonce key according to GravityView Edit Entry protocol
170
     *
171
     * @param $view_id int GravityView view id
172
     * @param $form_id int Gravity Forms form id
173
     * @param $entry_id int Gravity Forms entry id
174
     * @return string
175
     */
176 24
    public static function get_nonce_key( $view_id, $form_id, $entry_id ) {
177 24
        return sprintf( 'edit_%d_%d_%d', $view_id, $form_id, $entry_id );
178
    }
179
180
181
    /**
182
     * The edit entry link creates a secure link with a nonce
183
     *
184
     * It also mimics the URL structure Gravity Forms expects to have so that
185
     * it formats the display of the edit form like it does in the backend, like
186
     * "You can edit this post from the post page" fields, for example.
187
     *
188
     * @param $entry array Gravity Forms entry object
189
     * @param $view_id int GravityView view id
190
     * @param $post_id int GravityView Post ID where View may be embedded {@since 1.9.2}
191
     * @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/ }
192
     * @return string
193
     */
194 3
    public static function get_edit_link( $entry, $view_id, $post_id = null, $field_values = '' ) {
195
196 3
        $nonce_key = self::get_nonce_key( $view_id, $entry['form_id'], $entry['id']  );
197
198 3
        $base = gv_entry_link( $entry, $post_id ? : $view_id  );
199
200 3
        $url = add_query_arg( array(
201 3
            'edit' => wp_create_nonce( $nonce_key )
202 3
        ), $base );
203
204 3
        if( $post_id ) {
205 2
	        $url = add_query_arg( array( 'gvid' => $view_id ), $url );
206
        }
207
208
	    /**
209
	     * Allow passing params to dynamically populate entry with values
210
	     * @since 1.9.2
211
	     */
212 3
	    if( !empty( $field_values ) ) {
213
214
		    if( is_array( $field_values ) ) {
215
			    // If already an array, no parse_str() needed
216
			    $params = $field_values;
217
		    } else {
218
			    parse_str( $field_values, $params );
219
		    }
220
221
		    $url = add_query_arg( $params, $url );
222
	    }
223
224
		/**
225
		 * @filter `gravityview/edit/link` Filter the edit URL link.
226
		 * @param[in,out] string $url The url.
227
		 * @param array $entry The entry.
228
		 * @param \GV\View $view The View.
229
		 */
230 3
		return apply_filters( 'gravityview/edit/link', $url, $entry, \GV\View::by_id( $view_id  ) );
231
    }
232
233
	/**
234
	 * Edit mode doesn't allow certain field types.
235
	 * @param  array $fields  Existing blacklist fields
236
	 * @param  string|null $context Context
237
	 * @return array          If not edit context, original field blacklist. Otherwise, blacklist including post fields.
238
	 */
239
	public function modify_field_blacklist( $fields = array(), $context = NULL ) {
240
241
		if( empty( $context ) || $context !== 'edit' ) {
242
			return $fields;
243
		}
244
245
		$add_fields = $this->get_field_blacklist();
246
247
		return array_merge( $fields, $add_fields );
248
	}
249
250
	/**
251
	 * Returns array of field types that should not be displayed in Edit Entry
252
	 *
253
	 * @since 1.20
254
	 *
255
	 * @param array $entry Gravity Forms entry array
256
	 *
257
	 * @return array Blacklist of field types
258
	 */
259 22
	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...
260
261
		$fields = array(
262 22
			'page',
263
			'payment_status',
264
			'payment_date',
265
			'payment_amount',
266
			'is_fulfilled',
267
			'transaction_id',
268
			'transaction_type',
269
			'captcha',
270
			'honeypot',
271
			'creditcard',
272
		);
273
274
		/**
275
		 * @filter `gravityview/edit_entry/field_blacklist` Array of fields that should not be displayed in Edit Entry
276
		 * @since 1.20
277
		 * @param array $fields Blacklist field type array
278
		 * @param array $entry Gravity Forms entry array
279
		 */
280 22
		$fields = apply_filters( 'gravityview/edit_entry/field_blacklist', $fields, $entry );
281
282 22
		return $fields;
283
	}
284
285
286
    /**
287
     * checks if user has permissions to edit a specific entry
288
     *
289
     * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_entry for maximum security!!
290
     *
291
     * @param  array $entry Gravity Forms entry array
292
     * @param \GV\View int $view_id ID of the view you want to check visibility against {@since 1.9.2}. Required since 2.0
293
     * @return bool
294
     */
295 24
    public static function check_user_cap_edit_entry( $entry, $view = 0 ) {
296
297
        // No permission by default
298 24
        $user_can_edit = false;
299
300
		// get user_edit setting
301 24
		if ( empty( $view ) ) {
302
			// @deprecated path
303 22
			$view_id = GravityView_View::getInstance()->getViewId();
304 22
			$user_edit = GravityView_View::getInstance()->getAtts( 'user_edit' );
305
		} else {
306 2
			if ( $view instanceof \GV\View ) {
307
				$view_id = $view->ID;
308
			} else {
309 2
				$view_id = $view;
310
			}
311
312
			// in case is specified and not the current view
313 2
			$user_edit = GVCommon::get_template_setting( $view_id, 'user_edit' );
314
		}
315
316
        // If they can edit any entries (as defined in Gravity Forms)
317
        // Or if they can edit other people's entries
318
        // Then we're good.
319 24
        if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ), $entry['id'] ) ) {
320
321 23
            gravityview()->log->debug( 'User has ability to edit all entries.' );
322
323 23
            $user_can_edit = true;
324
325 3
        } else if( !isset( $entry['created_by'] ) ) {
326
327 1
            gravityview()->log->error( 'Entry `created_by` doesn\'t exist.');
328
329 1
            $user_can_edit = false;
330
331
        } else {
332
333
334 3
            $current_user = wp_get_current_user();
335
336
            // User edit is disabled
337 3
            if( empty( $user_edit ) ) {
338
339 2
                gravityview()->log->debug( 'User Edit is disabled. Returning false.' );
340
341 2
                $user_can_edit = false;
342
            }
343
344
            // User edit is enabled and the logged-in user is the same as the user who created the entry. We're good.
345 2
            else if( is_user_logged_in() && intval( $current_user->ID ) === intval( $entry['created_by'] ) ) {
346
347 2
                gravityview()->log->debug( 'User {user_id} created the entry.', array( 'user_id', $current_user->ID ) );
348
349 2
                $user_can_edit = true;
350
351 2
            } else if( ! is_user_logged_in() ) {
352
353
                gravityview()->log->debug( 'No user defined; edit entry requires logged in user' );
354
            }
355
356
        }
357
358
        /**
359
         * @filter `gravityview/edit_entry/user_can_edit_entry` Modify whether user can edit an entry.
360
         * @since 1.15 Added `$entry` and `$view_id` parameters
361
         * @param[in,out] boolean $user_can_edit Can the current user edit the current entry? (Default: false)
362
         * @param[in] array $entry Gravity Forms entry array {@since 1.15}
363
         * @param[in] int $view_id ID of the view you want to check visibility against {@since 1.15}
364
         */
365 24
        $user_can_edit = apply_filters( 'gravityview/edit_entry/user_can_edit_entry', $user_can_edit, $entry, $view_id );
366
367 24
        return (bool)$user_can_edit;
368
    }
369
370
371
372
} // end class
373
374
//add_action( 'plugins_loaded', array('GravityView_Edit_Entry', 'getInstance'), 6 );
375
GravityView_Edit_Entry::getInstance();
376
377