Completed
Push — master ( c00646...cd320e )
by Zack
11s
created

GravityView_Field_Notes::get_add_note_part()   B

Complexity

Conditions 8
Paths 11

Size

Total Lines 54
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 13.6169

Importance

Changes 0
Metric Value
cc 8
eloc 33
nc 11
nop 2
dl 0
loc 54
ccs 15
cts 27
cp 0.5556
crap 13.6169
rs 7.4119
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
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 17 and the first side effect is on line 870.

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
 * Notes Field
4
 *
5
 * @package     GravityView
6
 * @license     GPL2+
7
 * @since       1.17
8
 * @author      Katz Web Services, Inc.
9
 * @link        https://gravityview.co
10
 * @copyright   Copyright 2016, Katz Web Services, Inc.
11
 */
12
13
/**
14
 * Add Entry Notes
15
 * @since 1.17
16
 */
17
class GravityView_Field_Notes extends GravityView_Field {
18
19
	/**
20
	 * @var string Current __FILE__
21
	 * @since 1.17
22
	 */
23
	static $file;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $file.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

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

Loading history...
24
25
	/**
26
	 * @var string plugin_dir_path() of the current field file
27
	 * @since 1.17
28
	 */
29
	static $path;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $path.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

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

Loading history...
30
31
	/**
32
	 * @var bool Are we doing an AJAX request?
33
	 * @since 1.17
34
	 */
35
	private $doing_ajax = false;
36
37
	/**
38
	 * The name of the GravityView field type
39
	 * @var string
40
	 */
41
	var $name = 'notes';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $name.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

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

Loading history...
42
43
	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...
44
45
		self::$path = plugin_dir_path( __FILE__ );
46
		self::$file = __FILE__;
47
48
		$this->doing_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
49
50
		$this->add_hooks();
51
52
		parent::__construct();
53
	}
54
	
55
	/**
56
	 * Add AJAX hooks, [gv_note_add] shortcode, and template loading paths
57
	 *
58
	 * @since 1.17
59
	 *
60
	 * @return void
61
	 */
62
	private function add_hooks() {
63
64
		add_shortcode( 'gv_note_add', array( 'GravityView_Field_Notes', 'get_add_note_part' ) );
65
66
		add_action( 'wp', array( $this, 'maybe_delete_notes'), 1000 );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
67
		add_action( 'wp_ajax_nopriv_gv_delete_notes', array( $this, 'maybe_delete_notes') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
68
		add_action( 'wp_ajax_gv_delete_notes', array( $this, 'maybe_delete_notes') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
69
70
		add_action( 'wp', array( $this, 'maybe_add_note'), 1000 );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
71
		add_action( 'wp_ajax_nopriv_gv_note_add', array( $this, 'maybe_add_note') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
72
		add_action( 'wp_ajax_gv_note_add', array( $this, 'maybe_add_note') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
73
74
		// add template path to check for field
75
		add_filter( 'gravityview_template_paths', array( $this, 'add_template_path' ) );
76
		add_filter( 'gravityview/template/fields_template_paths', array( $this, 'add_template_path' ) );
77
78
		add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
79
		add_action( 'gravityview/field/notes/scripts', array( $this, 'enqueue_scripts' ) );
80
		
81
		add_filter( 'gravityview_entry_default_fields', array( $this, 'add_entry_default_field' ), 10, 3 );
82
	}
83
84
85
	/**
86
	 * Add Entry Notes to the Add Field picker in Edit View
87
	 *
88
	 * @see GravityView_Admin_Views::get_entry_default_fields()
89
	 *
90
	 * @since 1.17
91
	 *
92
	 * @param array $entry_default_fields Fields configured to show in the picker
93
	 * @param array $form Gravity Forms form array
94
	 * @param string $zone Current context: `directory`, `single`, `edit`
95
	 *
96
	 * @return array Fields array with notes added, if in Multiple Entries or Single Entry context
97
	 */
98
	public function add_entry_default_field( $entry_default_fields, $form, $zone ) {
99
100
		if( in_array( $zone, array( 'directory', 'single' ) ) ) {
101
			$entry_default_fields['notes'] = array(
102
				'label' => __( 'Entry Notes', 'gravityview' ),
103
				'type'  => 'notes',
104
				'desc'  => __( 'Display, add, and delete notes for an entry.', 'gravityview' ),
105
			);
106
		}
107
108
		return $entry_default_fields;
109
	}
110
111
	/**
112
	 * Register scripts and styles used by the Notes field
113
	 *
114
	 * @since 1.17
115
	 *
116
	 * @return void
117
	 */
118
	public function register_scripts() {
119
		$css_file = gravityview_css_url( 'entry-notes.css', GravityView_Field_Notes::$path . 'assets/css/' );
120
		wp_register_style( 'gravityview-notes', $css_file, array(), GravityView_Plugin::version );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
121
		wp_register_script( 'gravityview-notes', plugins_url( '/assets/js/entry-notes.js', GravityView_Field_Notes::$file ), array( 'jquery' ), GravityView_Plugin::version, true );
0 ignored issues
show
Deprecated Code introduced by
The constant GravityView_Plugin::version has been deprecated with message: Use \GV\Plugin::$version

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
122
	}
123
124
	/**
125
	 * Enqueue, localize field scripts and styles
126
	 * 
127
	 * @since 1.17
128
	 * 
129
	 * @return void
130
	 */
131 1
	public function enqueue_scripts() {
132 1
		global $wp_actions;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
133
134 1
		if( ! wp_script_is( 'gravityview-notes', 'enqueued' ) ) {
135 1
			wp_enqueue_style( 'gravityview-notes' );
136 1
			wp_enqueue_script( 'gravityview-notes' );
137
		}
138
139 1
		if( ! wp_script_is( 'gravityview-notes', 'done' ) ) {
140
141 1
			$strings = self::strings();
142
143 1
			wp_localize_script( 'gravityview-notes', 'GVNotes', array(
144 1
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
145
				'text' => array(
146 1
					'processing' => $strings['processing'],
147 1
					'delete_confirm' => $strings['delete-confirm'],
148 1
					'note_added' => $strings['added-note'],
149 1
					'error_invalid' => $strings['error-invalid'],
150 1
					'error_empty_note' => $strings['error-empty-note'],
151
				),
152
			) );
153
		}
154 1
	}
155
156
	/**
157
	 * Verify permissions, check if $_POST is set and as expected. If so, use process_add_note
158
	 *
159
	 * @since 1.17
160
	 *
161
	 * @see process_add_note
162
	 *
163
	 * @return void
164
	 */
165
	function maybe_add_note() {
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...
166
167
		if( ! GVCommon::has_cap( 'gravityview_add_entry_notes' ) ) {
168
			gravityview()->log->error( 'The user isnt allowed to add entry notes.' );
169
			return;
170
		}
171
172
		if( ! isset( $_POST['action'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
173
			return;
174
		}
175
176
		if( 'gv_note_add' === $_POST['action'] ) {
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
177
178
            if( ! GVCommon::has_cap( 'gravityview_add_entry_notes' ) ) {
179
                do_action( 'gravityview_log_error', __METHOD__ . ': The user isnt allowed to add entry notes.' );
180
                return;
181
            }
182
183
			$post = wp_unslash( $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
184
185
			if( $this->doing_ajax ) {
186
				parse_str( $post['data'], $data );
187
			} else {
188
				$data = $post;
189
			}
190
191
			$this->process_add_note( (array) $data );
192
		}
193
	}
194
195
	/**
196
	 * Handle adding a note.
197
	 *
198
	 * Verify the request. If valid, add the note. If AJAX request, send response JSON.
199
	 *
200
	 * @since 1.17
201
	 *
202
	 * @var array $data {
203
	 *  @type string $action "gv_note_add"
204
	 *  @type string $entry-slug Entry slug or ID to add note to
205
	 *  @type string $gv_note_add Nonce with action "gv_note_add_{entry slug}" and name "gv_note_add"
206
	 *  @type string $_wp_http_referer Relative URL to submitting page ('/view/example/entry/123/')
207
	 *  @type string $gv-note-content Note content
208
	 *  @type string $add_note Submit button value ('Add Note')
209
	 * }
210
	 *
211
	 * @return void
212
	 */
213
	private function process_add_note( $data ) {
214
215
		$error = false;
216
		$success = false;
217
218
		if( empty( $data['entry-slug'] ) ) {
219
220
			$error = self::strings('error-invalid');
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...
221
			gravityview()->log->error( 'The note is missing an Entry ID.' );
222
223
		} else {
224
225
			$valid = wp_verify_nonce( $data['gv_note_add'], 'gv_note_add_' . $data['entry-slug'] );
226
			
227
			$has_cap = GVCommon::has_cap( 'gravityview_add_entry_notes' );
228
229
			if( ! $has_cap ) {
230
				$error = self::strings( 'error-cap-add' );
231
				gravityview()->log->error( 'Adding a note failed: the user does not have the "gravityview_add_entry_notes" capability.' );
232
			} elseif ( $valid ) {
233
234
				$entry = gravityview_get_entry( $data['entry-slug'], true, false );
235
236
				$added = $this->add_note( $entry, $data );
237
238
				// Error adding note
239
				if ( is_wp_error( $added ) ) {
240
241
					$error = $added->get_error_message();
242
243
				} else {
244
245
					// Confirm the note was added, because GF doesn't return note ID on success
246
					$note = GravityView_Entry_Notes::get_note( $added );
247
248
					// Possibly email peeps about this great new note
249
					$this->maybe_send_entry_notes( $note, $entry, $data );
250
251
					if ( $note ) {
252
						$success = self::display_note( $note, ! empty( $data['show-delete'] ) );
253
						gravityview()->log->debug( 'The note was successfully created', array( 'data' => compact( 'note', 'data' ) ) );
254
					} else {
255
						$error = self::strings('error-add-note');
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...
256
						gravityview()->log->error( 'The note was not successfully created', array( 'data' => compact( 'note', 'data' ) ) );
257
					}
258
				}
259
			} else {
260
				$error = self::strings('error-invalid');
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...
261
				gravityview()->log->error( 'Nonce validation failed; the note was not created' );
262
			}
263
		}
264
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
265
266
		if( $this->doing_ajax ) {
267
			if( $success ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $success of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
268
				wp_send_json_success( array( 'html' => $success ) );
269
			} else {
270
				$error = $error ? $error : self::strings( 'error-invalid' );
271
				wp_send_json_error( array( 'error' => esc_html( $error ) ) );
272
			}
273
		}
274
	}
275
276
	/**
277
	 * Possibly delete notes, if request is proper.
278
	 *
279
	 * Verify permissions. Check expected $_POST. Parse args, then send to process_delete_notes
280
	 *
281
  	 * @since 1.17
282
	 *
283
	 * @see process_delete_notes
284
	 *
285
	 * @return void
286
	 */
287
	function maybe_delete_notes() {
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...
288
289
		if ( ! GVCommon::has_cap( 'gravityview_delete_entry_notes' ) ) {
290
			return;
291
		}
292
293
		if ( isset( $_POST['action'] ) && 'gv_delete_notes' === $_POST['action'] ) {
294
295
			$post = wp_unslash( $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
296
			if ( $this->doing_ajax ) {
297
				parse_str( $post['data'], $data );
298
			} else {
299
				$data = $post;
300
			}
301
302
			$required_args = array(
303
				'gv_delete_notes' => '',
304
				'entry-slug' => '',
305
			);
306
307
			$data = wp_parse_args( $data, $required_args );
308
309
			$this->process_delete_notes( $data );
310
		}
311
	}
312
313
	/**
314
	 * Handle deleting notes
315
	 *
316
	 * @var array $data {
317
	 *  @type string $action "gv_delete_notes"
318
	 *  @type string $entry-slug Entry slug or ID to add note to
319
	 *  @type string $gv_delete_notes Nonce with action "gv_delete_notes_{entry slug}" and name "gv_delete_notes"
320
	 *  @type string $_wp_http_referer Relative URL to submitting page ('/view/example/entry/123/')
321
	 *  @type int[]  $note  Array of Note IDs to be deleted
322
	 * }
323
	 *
324
	 * @return void
325
	 */
326
	function process_delete_notes( $data ) {
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...
327
328
		$valid = wp_verify_nonce( $data['gv_delete_notes'], 'gv_delete_notes_' . $data['entry-slug'] );
329
		$has_cap = GVCommon::has_cap( 'gravityview_delete_entry_notes' );
330
		$success = false;
331
332
		if ( $valid && $has_cap ) {
333
			GravityView_Entry_Notes::delete_notes( $data['note'] );
334
			$success = true;
335
		}
336
337
		if( $this->doing_ajax ) {
338
339
			if( $success ) {
340
				wp_send_json_success();
341
			} else {
342
				if ( ! $valid ) {
343
					$error_message = self::strings( 'error-invalid' );
344
				} else {
345
					$error_message = self::strings( 'error-permission-delete' );
346
				}
347
348
				wp_send_json_error( array( 'error' => $error_message ) );
349
			}
350
		}
351
	}
352
353
	/**
354
	 * Include this extension templates path
355
	 *
356
	 * @since 1.17
357
	 *
358
	 * @param array $file_paths List of template paths ordered
359
	 *
360
	 * @return array File paths with `./` and `./partials/` paths added
361
	 */
362 54
	public function add_template_path( $file_paths ) {
363
364 54
		$file_paths[ 172 ] = self::$path;
0 ignored issues
show
introduced by
Array keys should NOT be surrounded by spaces if they only contain a string or an integer.
Loading history...
365 54
		$file_paths[ 173 ] = self::$path . 'partials/';
0 ignored issues
show
introduced by
Array keys should NOT be surrounded by spaces if they only contain a string or an integer.
Loading history...
366
367 54
		return $file_paths;
368
	}
369
370
	public function field_options( $field_options, $template_id, $field_id, $context, $input_type ) {
371
372
		unset( $field_options['show_as_link'] );
373
374
		$notes_options = array(
375
			'notes' => array(
376
				'type' => 'checkboxes',
377
				'label' => __('Note Settings', 'gravityview'),
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...
378
				'desc' => sprintf( _x('Only users with specific capabilities will be able to view, add and delete notes. %sRead more%s.', '%s is opening and closing HTML link', 'gravityview' ), '<a href="https://docs.gravityview.co/article/311-gravityview-capabilities">', '</a>' ),
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
379
				'options' => array(
380
					'view' => array(
381
						'label' => __( 'Display notes?', 'gravityview' ),
382
					),
383
					'view_loggedout' => array(
384
						'label' => __( 'Display notes to users who are not logged-in?', 'gravityview' ),
385
						'requires' => 'view',
386
					),
387
					'add' => array(
388
						'label' => __( 'Enable adding notes?', 'gravityview' ),
389
					),
390
					'email' => array(
391
						'label' => __( 'Allow emailing notes?', 'gravityview' ),
392
						'requires' => 'add',
393
					),
394
					'delete' => array(
395
						'label' => __( 'Allow deleting notes?', 'gravityview' ),
396
					),
397
				),
398
				'value' => array( 'view' => 1, 'add' => 1, 'email' => 1 ),
399
			),
400
		);
401
402
		return $notes_options + $field_options;
403
	}
404
405
	/**
406
	 * Get strings used by the Entry Notes field
407
	 *
408
	 * Use `gravityview/field/notes/strings` filter to modify the strings
409
	 *
410
	 * @since 1.17
411
	 *
412
	 * @param string $key If set, return the string with the key of $key
413
	 *
414
	 * @return array|string Array of strings with keys and values. If $key is set, returns string. If missing $strings[ $key ], empty string.
415
	 */
416 1
	static public function strings( $key = '' ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
417
418
		$strings = array(
419 1
			'add-note' => __( 'Add Note', 'gravityview' ),
420 1
			'added-note' => __( 'Note added.', 'gravityview' ),
421 1
			'content-label' => __( 'Note Content', 'gravityview' ),
422 1
			'delete' => __( 'Delete', 'gravityview' ),
423 1
			'delete-confirm' => __( 'Are you sure you want to delete the selected notes?', 'gravityview' ),
424 1
			'caption' => __( 'Notes for this entry', 'gravityview' ),
425 1
			'toggle-notes' => __( 'Toggle all notes', 'gravityview' ),
426 1
			'no-notes' => __( 'There are no notes.', 'gravityview' ),
427 1
			'processing' => __( 'Processing&hellip;', 'gravityview' ),
428 1
			'other-email' => __( 'Other email address', 'gravityview' ),
429 1
			'email-label' => __( 'Email address', 'gravityview' ),
430 1
			'email-placeholder' => _x('[email protected]', 'Example email address used as a placeholder', 'gravityview'),
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...
431 1
			'subject-label' => __( 'Subject', 'gravityview' ),
432 1
			'subject' => __( 'Email subject', 'gravityview' ),
433 1
			'default-email-subject' => __( 'New entry note', 'gravityview' ),
434 1
            'email-footer' => __( 'This note was sent from {url}', 'gravityview' ),
435 1
			'also-email' => __( 'Also email this note to', 'gravityview' ),
436 1
			'error-add-note' => __( 'There was an error adding the note.', 'gravityview' ),
437 1
			'error-invalid' => __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ),
438 1
			'error-empty-note' => _x( 'Note cannot be blank.', 'Message to display when submitting a note without content.', 'gravityview' ),
439 1
			'error-cap-delete' => __( 'You don\'t have the ability to delete notes.', 'gravityview' ),
440 1
			'error-cap-add' => __( 'You don\'t have the ability to add notes.', 'gravityview' ),
441
		);
442
443
		/**
444
		 * @filter `gravityview/field/notes/strings` Modify the text used in the Entry Notes field. Sanitized by `esc_html` after return.
445
		 * @since 1.17
446
		 * @param array $strings Text in key => value pairs
447
		 */
448 1
		$strings = gv_map_deep( apply_filters( 'gravityview/field/notes/strings', $strings ), 'esc_html' );
449
450 1
		if( $key ) {
451 1
			return isset( $strings[ $key ] ) ? $strings[ $key ] : '';
452
		}
453
454 1
		return $strings;
455
	}
456
457
	/**
458
	 * Generate HTML output for a single note
459
	 *
460
	 * @since 1.17
461
	 *
462
	 * @param object $note Note object with id, user_id, date_created, value, note_type, user_name, user_email vars
463
	 * @param bool $show_delete Whether to show the bulk delete inputs
464
	 *
465
	 * @since 2.0
466
	 * @param \GV\Template_Context $context The context.
467
	 *
468
	 * @return string HTML
469
	 */
470 1
	static public function display_note( $note, $show_delete = false, $context = null ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
471
472 1
		if( ! is_object( $note ) ) {
473
			return '';
474
		}
475
476
		$note_content = array(
477 1
			'avatar'                 => get_avatar( $note->user_id, 48 ),
478 1
			'user_name'              => $note->user_name,
479 1
			'user_email'             => $note->user_email,
480 1
			'added_on'               => esc_html__( 'added on {date_created_formatted}', 'gravityview' ),
481 1
			'value'                  => wpautop( esc_html( $note->value ) ),
482 1
			'date_created'           => $note->date_created,
483 1
			'date_created_formatted' => GFCommon::format_date( $note->date_created, false ),
484 1
			'user_id'                => intval( $note->user_id ),
485 1
			'note_type'              => $note->note_type,
486 1
			'note_id'                => intval( $note->id ),
487
		);
488
489
		/**
490
		 * @filter `gravityview/field/notes/content` Modify the note content before rendering in the template
491
		 * @since 1.17
492
		 * @param array $note_content Array of note content that will be replaced in template files
493
		 * @param object $note Note object with id, user_id, date_created, value, note_type, user_name, user_email vars
494
		 * @param boolean $show_delete True: Notes are editable. False: no editing notes.
495
		 * @since 2.0
496
		 * @param \GV\Template_Context $context The context.
497
		 */
498 1
		$note_content = apply_filters( 'gravityview/field/notes/content', $note_content, $note, $show_delete, $context );
499
500 1
		$note_row_template = ( $show_delete && GVCommon::has_cap( 'gravityview_delete_entry_notes' ) ) ? 'row-editable' : 'row';
501
502 1
		if ( $context instanceof \GV\Template_Context ) {
503 1
504 1
		    ob_start();
505
		    $context->template->get_template_part( 'note', 'detail', true );
506
            $note_detail_html = ob_get_clean();
507
508
            ob_start();
509
			$context->template->get_template_part( 'note', $note_row_template, true );
510
			$note_row = ob_get_clean();
511
		} else {
512
			/** @deprecated path */
513
			ob_start();
514
			GravityView_View::getInstance()->get_template_part( 'note', 'detail' );
515
			$note_detail_html = ob_get_clean();
516 1
517 1
			ob_start();
518
			GravityView_View::getInstance()->get_template_part( 'note', $note_row_template );
519
			$note_row = ob_get_clean();
520
		}
521 1
522 1
		foreach ( $note_content as $tag => $value ) {
523 1
			$note_detail_html = str_replace( '{' . $tag . '}', $value, $note_detail_html );
524
		}
525
526
		$replacements = array(
527 1
			'{note_id}' => $note_content['note_id'],
528
			'{row_class}' => 'gv-note',
529 1
			'{note_detail}' => $note_detail_html
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
530 1
		);
531
532
		// Strip extra whitespace in template
533 1
		$output = gravityview_strip_whitespace( $note_row );
534
535
		foreach ( $replacements as $tag => $replacement ) {
536
			$output = str_replace( $tag, $replacement, $output );
537
		}
538
539
		return $output;
540
	}
541
542
	/**
543
	 * Add a note.
544
	 *
545
	 * @since 1.17
546
	 *
547
	 * @see GravityView_Entry_Notes::add_note This method is mostly a wrapper
548
	 *
549
	 * @param array $entry
550
	 * @param array $data Note details array
551
	 *
552
	 * @return int|WP_Error
553
	 */
554
	private function add_note( $entry, $data ) {
555
		global $current_user, $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
556
557
		$user_data = get_userdata( $current_user->ID );
558
559
		$note_content = trim( $data['gv-note-content'] );
560
561
		if( empty( $note_content ) ) {
562
			return new WP_Error( 'gv-add-note-empty', __( 'The note is empty.', 'gravityview' ) );
563
		}
564
565
		$return = GravityView_Entry_Notes::add_note( $entry['id'], $user_data->ID, $user_data->display_name, $note_content, 'gravityview/field/notes' );
566
567
		return $return;
568
	}
569
570
	/**
571
	 * Get the Add Note form HTML
572
	 *
573
	 * @since 1.17
574
	 *
575 1
	 * @since 2.0
576
	 * @param array $atts Shortcode attributes for entry ID
577 1
	 * @param \GV\Template_Context $context The context, when called outside of a shortcode
578
	 *
579 1
	 * @return string HTML of the Add Note form, or empty string if the user doesn't have the `gravityview_add_entry_notes` cap
580
	 */
581
	public static function get_add_note_part( $atts, $context = null ) {
582
583
		$atts = shortcode_atts( array( 'entry' => null ), $atts );
584 1
585 1
		if( ! GVCommon::has_cap( 'gravityview_add_entry_notes' ) ) {
586 1
			gravityview()->log->error( 'User does not have permission to add entry notes ("gravityview_add_entry_notes").' );
587 1
			return '';
588
		}
589
590
		if ( $context instanceof \GV\Template_Context ) {
591
592
			ob_start();
593
			$context->template->get_template_part( 'note', 'add-note', true );
594
			$add_note_html = ob_get_clean();
595
596
			$visibility_settings = $context->field->notes;
0 ignored issues
show
Bug introduced by
The property notes does not seem to exist in GV\Field.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
597
			$entry = $context->entry->as_entry();
598
		} else {
599
			$gravityview_view = GravityView_View::getInstance();
600
601
			ob_start();
602
			$gravityview_view->get_template_part( 'note', 'add-note' );
603
			$add_note_html = ob_get_clean();
604
605
			$visibility_settings = $gravityview_view->getCurrentFieldSetting( 'notes' );
606
607 1
			if ( $atts['entry'] ) {
608 1
				$entry = GFAPI::get_entry( $atts['entry'] );
609 1
			}
610
611
			if ( ! isset( $entry ) || ! $entry ) {
612 1
				$entry = $gravityview_view->getCurrentEntry();
613 1
			}
614
		}
615
616
		// Strip extra whitespace in template
617 1
		$add_note_html = gravityview_strip_whitespace( $add_note_html );
618 1
		$entry_slug = GravityView_API::get_entry_slug( $entry['id'], $entry );
619 1
		$nonce_field = wp_nonce_field( 'gv_note_add_' . $entry_slug, 'gv_note_add', false, false );
620 1
621 1
		// Only generate the dropdown if the field settings allow it
622
		$email_fields = '';
623 1
		if( ! empty( $visibility_settings['email'] ) ) {
624
			$email_fields = self::get_note_email_fields( $entry_slug );
625
		}
626
627
		$add_note_html = str_replace( '{entry_slug}', $entry_slug, $add_note_html );
628
		$add_note_html = str_replace( '{nonce_field}', $nonce_field, $add_note_html );
629
		$add_note_html = str_replace( '{show_delete}', intval( empty( $visibility_settings['delete'] ) ? 0 : $visibility_settings['delete'] ), $add_note_html );
630
		$add_note_html   = str_replace( '{email_fields}', $email_fields, $add_note_html );
631
		$add_note_html = str_replace( '{url}', esc_url_raw( add_query_arg( array() ) ), $add_note_html );
632
633
		return $add_note_html;
634
	}
635
636
	/**
637
	 * Get array of emails addresses from the stored entry
638
	 *
639
	 * @since 1.17
640
	 *
641
	 * @return array Array of email addresses connected to the entry
642
	 */
643
	private static function get_note_emails_array() {
644
645
		$gravityview_view = GravityView_View::getInstance();
646
647
		//getting email values
648
		$email_fields = GFCommon::get_email_fields( $gravityview_view->getForm() );
649
650
		$entry = $gravityview_view->getCurrentEntry();
651
652
		$note_emails = array();
653
654
		foreach ( $email_fields as $email_field ) {
655
			if ( ! empty( $entry["{$email_field->id}"] ) && is_email( $entry["{$email_field->id}"] ) ) {
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
656
				$note_emails[] = $entry["{$email_field->id}"];
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
657
			}
658
		}
659
660
		/**
661
		 * @filter `gravityview/field/notes/emails` Modify the dropdown values displayed in the "Also email note to" dropdown
662
		 * @since 1.17
663
		 * @param array $note_emails Array of email addresses connected to the entry
664
		 * @param array $entry Current entry
665
		 */
666
		$note_emails = apply_filters( 'gravityview/field/notes/emails', $note_emails, $entry );
667
668
		return (array) $note_emails;
669
	}
670
671
	/**
672
	 * Generate a HTML dropdown of email values based on email fields from the current form
673
	 *
674
	 * @uses get_note_emails_array
675
	 *
676
	 * @since 1.17
677
	 *
678
	 * @param int|string $entry_slug Current entry unique ID
679
	 *
680
	 * @return string HTML output
681
	 */
682
	private static function get_note_email_fields( $entry_slug = '' ) {
683
684
		if( ! GVCommon::has_cap( 'gravityview_email_entry_notes' ) ) {
685
			gravityview()->log->error( 'User does not have permission to email entry notes ("gravityview_email_entry_notes").' );
686
			return '';
687
		}
688
689
		$entry_slug_esc = esc_attr( $entry_slug );
690
691
		$note_emails = self::get_note_emails_array();
692
693
		$strings = self::strings();
694
695
		/**
696
		 * @filter `gravityview/field/notes/custom-email` Whether to include a Custom Email option for users to define a custom email to mail notes to
697
		 * @since 1.17
698
		 * @param bool $include_custom Default: true
699
		 */
700
		$include_custom = apply_filters( 'gravityview/field/notes/custom-email', true );
701
702
		ob_start();
703
704
		if ( ! empty( $note_emails ) || $include_custom ) { ?>
705
			<div class="gv-note-email-container">
706
				<label for="gv-note-email-to-<?php echo $entry_slug_esc; ?>" class="screen-reader-text"><?php echo $strings['also-email'];  ?></label>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
707
				<select class="gv-note-email-to" name="gv-note-to" id="gv-note-email-to-<?php echo $entry_slug_esc; ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
708
					<option value=""><?php echo $strings['also-email'];  ?></option>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
709
					<?php foreach ( $note_emails as  $email ) {
710
						?>
711
						<option value="<?php echo esc_attr( $email ); ?>"><?php echo esc_html( $email ); ?></option>
712
					<?php }
713
					if( $include_custom ) { ?>
714
					<option value="custom"><?php echo self::strings('other-email'); ?></option>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
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...
715
					<?php } ?>
716
				</select>
717
				<fieldset class="gv-note-to-container">
718
					<?php if( $include_custom ) { ?>
719
					<div class='gv-note-to-custom-container'>
720
						<label for="gv-note-email-to-custom-<?php echo $entry_slug_esc; ?>"><?php echo $strings['email-label']; ?></label>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
721
						<input type="text" name="gv-note-to-custom" placeholder="<?php echo $strings['email-placeholder']; ?>" id="gv-note-to-custom-<?php echo $entry_slug_esc; ?>" value="" />
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
722
					</div>
723
					<?php } ?>
724
		            <div class='gv-note-subject-container'>
725
		                <label for="gv-note-subject-<?php echo $entry_slug_esc; ?>"><?php echo $strings['subject-label']; ?></label>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
726
		                <input type="text" name="gv-note-subject" placeholder="<?php echo $strings['subject']; ?>" id="gv-note-subject-<?php echo $entry_slug_esc; ?>" value="" />
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$strings'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$entry_slug_esc'
Loading history...
727
		            </div>
728
				</fieldset>
729
			</div>
730
		<?php }
731
732
		// TODO: Add a filter
733
		return ob_get_clean();
734
	}
735
736
	/**
737
	 * If note has an email to send, and the user has the right caps, send it
738
	 *
739
	 * @since 1.17
740
	 *
741
	 * @param false|object $note If note was created, object. Otherwise, false.
742
	 * @param array $entry Entry data
743
	 * @param array $data $_POST data
744
	 *
745
	 * @return void Tap in to Gravity Forms' `gform_after_email` action if you want a return result from sending the email.
746
	 */
747
	private function maybe_send_entry_notes( $note = false, $entry, $data ) {
748
749
		if( ! $note || ! GVCommon::has_cap('gravityview_email_entry_notes') ) {
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...
750
			gravityview()->log->debug( 'User doesn\'t have "gravityview_email_entry_notes" cap, or $note is empty', array( 'data' => $note ) );
751
			return;
752
		}
753
754
		gravityview()->log->debug( '$data', array( 'data' => $data ) );
755
756
		//emailing notes if configured
757
		if ( ! empty( $data['gv-note-to'] ) ) {
758
759
			$default_data = array(
760
				'gv-note-to' => '',
761
				'gv-note-to-custom' => '',
762
				'gv-note-subject' => '',
763
				'gv-note-content' => '',
764
                'current-url' => '',
765
			);
766
767
			$current_user  = wp_get_current_user();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
768
			$email_data = wp_parse_args( $data, $default_data );
769
770
			$from    = $current_user->user_email;
771
			$to = $email_data['gv-note-to'];
772
773
			/**
774
			 * Documented in get_note_email_fields
775
			 * @see get_note_email_fields
776
			 */
777
			$include_custom = apply_filters( 'gravityview/field/notes/custom-email', true );
778
779
			if( 'custom' === $to && $include_custom ) {
780
				$to = $email_data['gv-note-to-custom'];
781
				gravityview()->log->debug( 'Sending note to a custom email address: {to}' . array( 'to' => $to ) );
782
			}
783
784
			if ( ! GFCommon::is_valid_email_list( $to ) ) {
785
				gravityview()->log->error( '$to not a valid email or email list (CSV of emails): {to}', array( 'to' => print_r( $to, true ), 'data' => $email_data ) );
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
786
				return;
787
			}
788
789
			$bcc = false;
790
			$reply_to = $from;
791
			$subject = trim( $email_data['gv-note-subject'] );
792
793
			// We use empty() here because GF uses empty to check against, too. `0` isn't a valid subject to GF
794
			$subject = empty( $subject ) ? self::strings( 'default-email-subject' ) : $subject;
795
			$message = $email_data['gv-note-content'];
796
			$email_footer = self::strings( 'email-footer' );
797
			$from_name     = $current_user->display_name;
798
			$message_format = 'html';
799
800
			/**
801
			 * @filter `gravityview/field/notes/email_content` Modify the values passed when sending a note email
802
			 * @see GVCommon::send_email
803
			 * @since 1.17
804
			 * @param[in,out] array $email_settings Values being passed to the GVCommon::send_email() method: 'from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'entry', 'email_footer'
805
			 */
806
			$email_content = apply_filters( 'gravityview/field/notes/email_content', compact( 'from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'entry', 'email_footer' ) );
807
808
			extract( $email_content );
0 ignored issues
show
introduced by
extract() usage is highly discouraged, due to the complexity and unintended issues it might cause.
Loading history...
809
810
			$is_html = ( 'html' === $message_format );
811
812
			// Add the message footer
813
			$message .= $this->get_email_footer( $email_footer, $is_html, $email_data );
814
815
			/**
816
             * @filter `gravityview/field/notes/wpautop_email` Should the message content have paragraphs added automatically, if using HTML message format
817
			 * @since 1.18
818
             * @param bool $wpautop_email True: Apply wpautop() to the email message if using; False: Leave as entered (Default: true)
819
			 */
820
			$wpautop_email = apply_filters( 'gravityview/field/notes/wpautop_email', true );
821
822
			if ( $is_html && $wpautop_email ) {
823
				$message = wpautop( $message );
824
			}
825
826
			GVCommon::send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name, $message_format, '', $entry, false );
827
828
			$form  = isset( $entry['form_id'] ) ? GFAPI::get_form( $entry['form_id'] ) : array();
829
830
			/**
831
			 * @see https://www.gravityhelp.com/documentation/article/10146-2/ It's here for compatibility with Gravity Forms
832
			 */
833
			do_action( 'gform_post_send_entry_note', __METHOD__, $to, $from, $subject, $message, $form, $entry );
834
		}
835
	}
836
837
	/**
838
     * Get the footer for Entry Note emails
839
     *
840
     * `{url}` is replaced by the URL of the page where the note form was embedded
841
     *
842
     * @since 1.18
843
     * @see GravityView_Field_Notes::strings The default value of $message_footer is set here, with the key 'email-footer'
844
	 *
845
	 * @param string $email_footer The message footer value
846
	 * @param bool $is_html True: Email is being sent as HTML; False: sent as text
847
	 *
848
	 * @return string If email footer is not empty, return the message with placeholders replaced with dynamic values
849
	 */
850
	private function get_email_footer( $email_footer = '', $is_html = true, $email_data = array() ) {
851
852
	    $output = '';
853
854
		if( ! empty( $email_footer ) ) {
855
		    $url = \GV\Utils::get( $email_data, 'current-url' );
856
			$url = html_entity_decode( $url );
857
			$url = site_url( $url );
858
859
			$content = $is_html ? "<a href='{$url}'>{$url}</a>" : $url;
860
861
			$email_footer = str_replace( '{url}', $content, $email_footer );
862
863
			$output .= "\n\n$email_footer";
864
		}
865
866
		return $output;
867
	}
868
}
869
870
new GravityView_Field_Notes;
871