Completed
Push — master ( 5d7bd1...022e44 )
by Zack
04:13
created

GravityView_Field_Notes::enqueue_scripts()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 15
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 24
rs 8.9713
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 738.

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
77
		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...
78
		add_action( 'gravityview/field/notes/scripts', array( $this, 'enqueue_scripts' ) );
79
	}
80
81
	/**
82
	 * Register scripts and styles used by the Notes field
83
	 *
84
	 * @since 1.17
85
	 *
86
	 * @return void
87
	 */
88
	public function register_scripts() {
89
		$css_file = gravityview_css_url( 'entry-notes.css', GravityView_Field_Notes::$path . 'assets/css/' );
90
		wp_register_style( 'gravityview-notes', $css_file, array(), GravityView_Plugin::version );
91
		wp_register_script( 'gravityview-notes', plugins_url( '/assets/js/entry-notes.js', GravityView_Field_Notes::$file ), array( 'jquery' ), GravityView_Plugin::version, true );
92
	}
93
94
	/**
95
	 * Enqueue, localize field scripts and styles
96
	 * 
97
	 * @since 1.17
98
	 * 
99
	 * @return void
100
	 */
101
	public function enqueue_scripts() {
102
		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...
103
104
		if( ! wp_script_is( 'gravityview-notes', 'enqueued' ) ) {
105
			wp_enqueue_style( 'gravityview-notes' );
106
			wp_enqueue_script( 'gravityview-notes' );
107
		}
108
109
		if( ! wp_script_is( 'gravityview-notes', 'done' ) ) {
110
111
			$strings = self::strings();
112
113
			wp_localize_script( 'gravityview-notes', 'GVNotes', array(
114
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
115
				'text' => array(
116
					'processing' => $strings['processing'],
117
					'delete_confirm' => $strings['delete-confirm'],
118
					'note_added' => $strings['added-note'],
119
					'error_invalid' => $strings['error-invalid'],
120
					'error_empty_note' => $strings['error-empty-note'],
121
				),
122
			) );
123
		}
124
	}
125
126
	/**
127
	 * Verify permissions, check if $_POST is set and as expected. If so, use process_add_note
128
	 *
129
	 * @since 1.17
130
	 *
131
	 * @see process_add_note
132
	 *
133
	 * @return void
134
	 */
135
	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...
136
137
		if( ! GVCommon::has_cap( 'gravityview_add_entry_notes' ) ) {
138
			do_action( 'gravityview_log_error', __METHOD__ . ': The user isnt allowed to add entry notes.' );
139
			return;
140
		}
141
142
		if( 'gv_note_add' === rgpost('action') ) {
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...
143
144
			$post = wp_unslash( $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
145
146
			if( $this->doing_ajax ) {
147
				parse_str( $post['data'], $data );
148
			} else {
149
				$data = $post;
150
			}
151
152
			$this->process_add_note( (array) $data );
153
		}
154
	}
155
156
	/**
157
	 * Handle adding a note.
158
	 *
159
	 * Verify the request. If valid, add the note. If AJAX request, send response JSON.
160
	 *
161
	 * @since 1.17
162
	 *
163
	 * @var array $data {
164
	 *  @type string $action "gv_note_add"
165
	 *  @type string $entry-slug Entry slug or ID to add note to
166
	 *  @type string $gv_note_add Nonce with action "gv_note_add_{entry slug}" and name "gv_note_add"
167
	 *  @type string $_wp_http_referer Relative URL to submitting page ('/view/example/entry/123/')
168
	 *  @type string $gv-note-content Note content
169
	 *  @type string $add_note Submit button value ('Add Note')
170
	 * }
171
	 *
172
	 * @return void
173
	 */
174
	private function process_add_note( $data ) {
175
176
		$error = false;
177
		$success = false;
178
179
		if( empty( $data['entry-slug'] ) ) {
180
181
			$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...
182
			do_action( 'gravityview_log_error', __METHOD__ . ': The note is missing an Entry ID.' );
183
184
		} else {
185
186
			$valid = wp_verify_nonce( $data['gv_note_add'], 'gv_note_add_' . $data['entry-slug'] );
187
			
188
			$has_cap = GVCommon::has_cap( 'gravityview_add_entry_notes' );
189
190
			if( ! $has_cap ) {
191
				$error = self::strings( 'error-cap-add' );
192
				do_action( 'gravityview_log_error', __METHOD__ . ': Adding a note failed: the user does not have the "gravityview_add_entry_notes" capability.' );
193
			} elseif ( $valid ) {
194
195
				$entry = gravityview_get_entry( $data['entry-slug'], true, false );
196
197
				$added = $this->add_note( $entry, $data );
198
199
				// Error adding note
200
				if ( is_wp_error( $added ) ) {
201
202
					$error = $added->get_error_message();
203
204
				} else {
205
206
					// Confirm the note was added, because GF doesn't return note ID on success
207
					$note = GravityView_Entry_Notes::get_note( $added );
208
209
					// Possibly email peeps about this great new note
210
					$this->maybe_send_entry_notes( $note, $entry, $data );
211
212
					if ( $note ) {
213
						$success = self::display_note( $note, ! empty( $data['show-delete'] ) );
214
						do_action( 'gravityview_log_debug', __METHOD__ . ': The note was successfully created', compact('note', 'data') );
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...
215
					} else {
216
						$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...
217
						do_action( 'gravityview_log_error', __METHOD__ . ': The note was not successfully created', compact('note', 'data') );
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...
218
					}
219
				}
220
			} else {
221
				$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...
222
				do_action( 'gravityview_log_error', __METHOD__ . ': Nonce validation failed; the note was not created' );
223
			}
224
		}
225
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
226
227
		if( $this->doing_ajax ) {
228
			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...
229
				wp_send_json_success( array( 'html' => $success ) );
230
			} else {
231
				$error = $error ? $error : self::strings( 'error-invalid' );
232
				wp_send_json_error( array( 'error' => esc_html( $error ) ) );
233
			}
234
		}
235
	}
236
237
	/**
238
	 * Possibly delete notes, if request is proper.
239
	 *
240
	 * Verify permissions. Check expected $_POST. Parse args, then send to process_delete_notes
241
	 *
242
  	 * @since 1.17
243
	 *
244
	 * @see process_delete_notes
245
	 *
246
	 * @return void
247
	 */
248
	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...
249
250
		if ( ! GVCommon::has_cap( 'gravityview_delete_entry_notes' ) ) {
251
			return;
252
		}
253
254
		if ( isset( $_POST['action'] ) && 'gv_delete_notes' === $_POST['action'] ) {
255
256
			$post = wp_unslash( $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
257
			if ( $this->doing_ajax ) {
258
				parse_str( $post['data'], $data );
259
			} else {
260
				$data = $post;
261
			}
262
263
			$required_args = array(
264
				'gv_delete_notes' => '',
265
				'entry-slug' => '',
266
			);
267
268
			$data = wp_parse_args( $data, $required_args );
269
270
			$this->process_delete_notes( $data );
271
		}
272
	}
273
274
	/**
275
	 * Handle deleting notes
276
	 *
277
	 * @var array $data {
278
	 *  @type string $action "gv_delete_notes"
279
	 *  @type string $entry-slug Entry slug or ID to add note to
280
	 *  @type string $gv_delete_notes Nonce with action "gv_delete_notes_{entry slug}" and name "gv_delete_notes"
281
	 *  @type string $_wp_http_referer Relative URL to submitting page ('/view/example/entry/123/')
282
	 *  @type int[]  $note  Array of Note IDs to be deleted
283
	 * }
284
	 *
285
	 * @return void
286
	 */
287
	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...
288
289
		$valid = wp_verify_nonce( $data['gv_delete_notes'], 'gv_delete_notes_' . $data['entry-slug'] );
290
		$has_cap = GVCommon::has_cap( 'gravityview_delete_entry_notes' );
291
		$success = false;
292
293
		if ( $valid && $has_cap ) {
294
			GravityView_Entry_Notes::delete_notes( $data['note'] );
295
			$success = true;
296
		}
297
298
		if( $this->doing_ajax ) {
299
300
			if( $success ) {
301
				wp_send_json_success();
302
			} else {
303
				if ( ! $valid ) {
304
					$error_message = self::strings( 'error-invalid' );
305
				} else {
306
					$error_message = self::strings( 'error-permission-delete' );
307
				}
308
309
				wp_send_json_error( array( 'error' => $error_message ) );
310
			}
311
		}
312
	}
313
314
	/**
315
	 * Include this extension templates path
316
	 *
317
	 * @since 1.17
318
	 *
319
	 * @param array $file_paths List of template paths ordered
320
	 *
321
	 * @return array File paths with `./` and `./partials/` paths added
322
	 */
323
	public function add_template_path( $file_paths ) {
324
325
		$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...
326
		$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...
327
328
		return $file_paths;
329
	}
330
331
	public function field_options( $field_options, $template_id, $field_id, $context, $input_type ) {
332
333
		unset( $field_options['show_as_link'] );
334
335
		$notes_options = array(
336
			'notes' => array(
337
				'type' => 'checkboxes',
338
				'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...
339
				'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...
340
				'options' => array(
341
					'view' => array(
342
						'label' => __( 'Display notes?', 'gravityview' ),
343
					),
344
					'view_loggedout' => array(
345
						'label' => __( 'Display notes to users who are not logged-in?', 'gravityview' ),
346
						'requires' => 'view',
347
					),
348
					'add' => array(
349
						'label' => __( 'Enable adding notes?', 'gravityview' ),
350
					),
351
					'email' => array(
352
						'label' => __( 'Allow emailing notes?', 'gravityview' ),
353
						'requires' => 'add',
354
					),
355
					'delete' => array(
356
						'label' => __( 'Allow deleting notes?', 'gravityview' ),
357
					),
358
				),
359
				'value' => array( 'view', 'add', 'email' ),
360
			),
361
		);
362
363
		return $notes_options + $field_options;
364
	}
365
366
	/**
367
	 * Get strings used by the Entry Notes field
368
	 *
369
	 * Use `gravityview/field/notes/strings` filter to modify the strings
370
	 *
371
	 * @since 1.17
372
	 *
373
	 * @param string $key If set, return the string with the key of $key
374
	 *
375
	 * @return array|string Array of strings with keys and values. If $key is set, returns string. If missing $strings[ $key ], empty string.
376
	 */
377
	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...
378
379
		$strings = array(
380
			'add-note' => __( 'Add Note', 'gravityview' ),
381
			'added-note' => __( 'Note added.', 'gravityview' ),
382
			'content-label' => __( 'Note Content', 'gravityview' ),
383
			'delete' => __( 'Delete', 'gravityview' ),
384
			'delete-confirm' => __( 'Are you sure you want to delete the selected notes?', 'gravityview' ),
385
			'caption' => __( 'Notes for this entry', 'gravityview' ),
386
			'toggle-notes' => __( 'Toggle all notes', 'gravityview' ),
387
			'no-notes' => __( 'There are no notes.', 'gravityview' ),
388
			'processing' => __( 'Processing&hellip;', 'gravityview' ),
389
			'other-email' => __( 'Other email address', 'gravityview' ),
390
			'email-label' => __( 'Email address', 'gravityview' ),
391
			'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...
392
			'subject-label' => __( 'Subject', 'gravityview' ),
393
			'subject' => __( 'Email subject', 'gravityview' ),
394
			'default-email-subject' => __( 'New entry note', 'gravityview' ),
395
			'also-email' => __( 'Also email this note to', 'gravityview' ),
396
			'error-add-note' => __( 'There was an error adding the note.', 'gravityview' ),
397
			'error-invalid' => __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ),
398
			'error-empty-note' => _x( 'Note cannot be blank.', 'Message to display when submitting a note without content.', 'gravityview' ),
399
			'error-cap-delete' => __( 'You don\'t have the ability to delete notes.', 'gravityview' ),
400
			'error-cap-add' => __( 'You don\'t have the ability to add notes.', 'gravityview' ),
401
		);
402
403
		/**
404
		 * @filter `gravityview/field/notes/strings` Modify the text used in the Entry Notes field. Sanitized by `esc_html` after return.
405
		 * @since 1.17
406
		 * @param array $strings Text in key => value pairs
407
		 */
408
		$strings = gv_map_deep( apply_filters( 'gravityview/field/notes/strings', $strings ), 'esc_html' );
409
410
		if( $key ) {
411
			return isset( $strings[ $key ] ) ? $strings[ $key ] : '';
412
		}
413
414
		return $strings;
415
	}
416
417
	/**
418
	 * Generate HTML output for a single note
419
	 *
420
	 * @since 1.17
421
	 *
422
	 * @param object $note Note object with id, user_id, date_created, value, note_type, user_name, user_email vars
423
	 * @param bool $show_delete Whether to show the bulk delete inputs
424
	 *
425
	 * @return string HTML
426
	 */
427
	static public function display_note( $note, $show_delete = false ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
428
429
		if( ! is_object( $note ) ) {
430
			return '';
431
		}
432
433
		$note_content = array(
434
			'avatar'                 => get_avatar( $note->user_id, 48 ),
435
			'user_name'              => $note->user_name,
436
			'user_email'             => $note->user_email,
437
			'added_on'               => esc_html__( 'added on {date_created_formatted}', 'gravityview' ),
438
			'value'                  => wpautop( esc_html( $note->value ) ),
439
			'date_created'           => $note->date_created,
440
			'date_created_formatted' => GFCommon::format_date( $note->date_created, false ),
441
			'user_id'                => intval( $note->user_id ),
442
			'note_type'              => $note->note_type,
443
			'note_id'                => intval( $note->id ),
444
		);
445
446
		/**
447
		 * @filter `gravityview/field/notes/content` Modify the note content before rendering in the template
448
		 * @since 1.17
449
		 * @param array $note_content Array of note content that will be replaced in template files
450
		 * @param object $note Note object with id, user_id, date_created, value, note_type, user_name, user_email vars
451
		 * @param boolean $show_delete True: Notes are editable. False: no editing notes.
452
		 */
453
		$note_content = apply_filters( 'gravityview/field/notes/content', $note_content, $note, $show_delete );
454
455
		ob_start();
456
		GravityView_View::getInstance()->get_template_part( 'note', 'detail' );
457
		$note_detail_html = ob_get_clean();
458
459
		foreach ( $note_content as $tag => $value ) {
460
			$note_detail_html = str_replace( '{' . $tag . '}', $value, $note_detail_html );
461
		}
462
463
		$note_row_template = ( $show_delete && GVCommon::has_cap( 'gravityview_delete_entry_notes' ) ) ? 'row-editable' : 'row';
464
465
		ob_start();
466
		GravityView_View::getInstance()->get_template_part( 'note', $note_row_template );
467
		$note_row = ob_get_clean();
468
469
		$replacements = array(
470
			'{note_id}' => $note_content['note_id'],
471
			'{row_class}' => 'gv-note',
472
			'{note_detail}' => $note_detail_html
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
473
		);
474
475
		// Strip extra whitespace in template
476
		$output = normalize_whitespace( $note_row );
477
478
		foreach ( $replacements as $tag => $replacement ) {
479
			$output = str_replace( $tag, $replacement, $output );
480
		}
481
482
		return $output;
483
	}
484
485
	/**
486
	 * Add a note.
487
	 *
488
	 * @since 1.17
489
	 *
490
	 * @see GravityView_Entry_Notes::add_note This method is mostly a wrapper
491
	 *
492
	 * @param array $entry
493
	 * @param array $data Note details array
494
	 *
495
	 * @return int|WP_Error
496
	 */
497
	private function add_note( $entry, $data ) {
498
		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...
499
500
		$user_data = get_userdata( $current_user->ID );
501
502
		$note_content = trim( $data['gv-note-content'] );
503
504
		if( empty( $note_content ) ) {
505
			return new WP_Error( 'gv-add-note-empty', __( 'The note is empty.', 'gravityview' ) );
506
		}
507
508
		$return = GravityView_Entry_Notes::add_note( $entry['id'], $user_data->ID, $user_data->display_name, $note_content, 'gravityview/field/notes' );
509
510
		return $return;
511
	}
512
513
	/**
514
	 * Get the Add Note form HTML
515
	 *
516
	 * @todo Allow passing entry_id as a shortcode parameter to set entry from shortcode
517
	 *
518
	 * @since 1.17
519
	 *
520
	 * @return string HTML of the Add Note form, or empty string if the user doesn't have the `gravityview_add_entry_notes` cap
521
	 */
522
	public static function get_add_note_part() {
523
524
		if( ! GVCommon::has_cap( 'gravityview_add_entry_notes' ) ) {
525
			do_action( 'gravityview_log_error', __METHOD__ . ': User does not have permission to add entry notes ("gravityview_add_entry_notes").' );
526
			return '';
527
		}
528
529
		$gravityview_view = GravityView_View::getInstance();
530
531
		ob_start();
532
		$gravityview_view->get_template_part( 'note', 'add-note' );
533
		$add_note_html = ob_get_clean();
534
535
		$visibility_settings = $gravityview_view->getCurrentFieldSetting( 'notes' );
536
		$entry = $gravityview_view->getCurrentEntry();
537
		$entry_slug = GravityView_API::get_entry_slug( $entry['id'], $entry );
538
		$nonce_field = wp_nonce_field( 'gv_note_add_' . $entry_slug, 'gv_note_add', false, false );
539
540
		// Only generate the dropdown if the field settings allow it
541
		$email_fields = '';
542
		if( ! empty( $visibility_settings['email'] ) ) {
543
			$email_fields = self::get_note_email_fields( $entry_slug );
544
		}
545
546
		$add_note_html = str_replace( '{entry_slug}', $entry_slug, $add_note_html );
547
		$add_note_html = str_replace( '{nonce_field}', $nonce_field, $add_note_html );
548
		$add_note_html = str_replace( '{show_delete}', intval( $visibility_settings['delete'] ), $add_note_html );
549
		$add_note_html   = str_replace( '{email_fields}', $email_fields, $add_note_html );
550
551
		return $add_note_html;
552
	}
553
554
	/**
555
	 * Get array of emails addresses from the stored entry
556
	 *
557
	 * @since 1.17
558
	 *
559
	 * @return array Array of email addresses connected to the entry
560
	 */
561
	private static function get_note_emails_array() {
562
563
		$gravityview_view = GravityView_View::getInstance();
564
565
		//getting email values
566
		$email_fields = GFCommon::get_email_fields( $gravityview_view->getForm() );
567
568
		$entry = $gravityview_view->getCurrentEntry();
569
570
		$note_emails = array();
571
572
		foreach ( $email_fields as $email_field ) {
573
			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...
574
				$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...
575
			}
576
		}
577
578
		/**
579
		 * @filter `gravityview/field/notes/emails` Modify the dropdown values displayed in the "Also email note to" dropdown
580
		 * @since 1.17
581
		 * @param array $note_emails Array of email addresses connected to the entry
582
		 * @param array $entry Current entry
583
		 */
584
		$note_emails = apply_filters( 'gravityview/field/notes/emails', $note_emails, $entry );
585
586
		return (array) $note_emails;
587
	}
588
589
	/**
590
	 * Generate a HTML dropdown of email values based on email fields from the current form
591
	 *
592
	 * @uses get_note_emails_array
593
	 *
594
	 * @since 1.17
595
	 *
596
	 * @param int|string $entry_slug Current entry unique ID
597
	 *
598
	 * @return string HTML output
599
	 */
600
	private static function get_note_email_fields( $entry_slug = '' ) {
601
602
		if( ! GVCommon::has_cap( 'gravityview_email_entry_notes' ) ) {
603
			do_action( 'gravityview_log_error', __METHOD__ . ': User does not have permission to email entry notes ("gravityview_email_entry_notes").' );
604
			return '';
605
		}
606
607
		$entry_slug_esc = esc_attr( $entry_slug );
608
609
		$note_emails = self::get_note_emails_array();
610
611
		$strings = self::strings();
612
613
		/**
614
		 * @filter `gravityview/field/notes/custom-email` Whether to include a Custom Email option for users to define a custom email to mail notes to
615
		 * @since 1.17
616
		 * @param bool $include_custom Default: true
617
		 */
618
		$include_custom = apply_filters( 'gravityview/field/notes/custom-email', true );
619
620
		ob_start();
621
622
		if ( ! empty( $note_emails ) || $include_custom ) { ?>
623
			<div class="gv-note-email-container">
624
				<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...
625
				<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...
626
					<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...
627
					<?php foreach ( $note_emails as  $email ) {
628
						?>
629
						<option value="<?php echo esc_attr( $email ); ?>"><?php echo esc_html( $email ); ?></option>
630
					<?php }
631
					if( $include_custom ) { ?>
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 0 tabs, found 5
Loading history...
632
					<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...
633
					<?php } ?>
634
				</select>
635
				<fieldset class="gv-note-to-container">
636
					<?php if( $include_custom ) { ?>
637
					<div class='gv-note-to-custom-container'>
638
						<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...
639
						<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...
640
					</div>
641
					<?php } ?>
642
		            <div class='gv-note-subject-container'>
643
		                <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...
644
		                <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...
645
		            </div>
646
				</fieldset>
647
			</div>
648
		<?php }
649
650
		// TODO: Add a filter
651
		return ob_get_clean();
652
	}
653
654
	/**
655
	 * If note has an email to send, and the user has the right caps, send it
656
	 *
657
	 * @since 1.17
658
	 *
659
	 * @param false|object $note If note was created, object. Otherwise, false.
660
	 * @param array $entry Entry data
661
	 * @param array $data $_POST data
662
	 *
663
	 * @return void Tap in to Gravity Forms' `gform_after_email` action if you want a return result from sending the email.
664
	 */
665
	private function maybe_send_entry_notes( $note = false, $entry, $data ) {
666
667
		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...
668
			do_action( 'gravityview_log_debug', __METHOD__ . ': User doesnt have "gravityview_email_entry_notes" cap, or $note is empty', $note );
669
			return;
670
		}
671
672
		do_action( 'gravityview_log_debug', __METHOD__ . ': $data', $data );
673
674
		//emailing notes if configured
675
		if ( ! empty( $data['gv-note-to'] ) ) {
676
677
			$default_data = array(
678
				'gv-note-to' => '',
679
				'gv-note-to-custom' => '',
680
				'gv-note-subject' => '',
681
				'gv-note-content' => '',
682
			);
683
684
			$current_user  = wp_get_current_user();
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
685
			$email_data = wp_parse_args( $data, $default_data );
686
687
			$from    = $current_user->user_email;
688
			$to = $email_data['gv-note-to'];
689
690
			/**
691
			 * Documented in get_note_email_fields
692
			 * @see get_note_email_fields
693
			 */
694
			$include_custom = apply_filters( 'gravityview/field/notes/custom-email', true );
695
696
			if( 'custom' === $to && $include_custom ) {
697
				$to = $email_data['gv-note-to-custom'];
698
				do_action( 'gravityview_log_debug', __METHOD__ . ': Sending note to a custom email address: ' . $to );
699
			}
700
701
			if ( ! is_email( $to ) ) {
702
				do_action( 'gravityview_log_error', __METHOD__ . ': $to not a valid email address: ' . $to, $email_data );
703
				return;
704
			}
705
706
			$bcc = false;
707
			$reply_to = $from;
708
			$subject = trim( $email_data['gv-note-subject'] );
709
710
			// We use empty() here because GF uses empty to check against, too. `0` isn't a valid subject to GF
711
			$subject = empty( $subject ) ? self::strings( 'default-email-subject' ) : $subject;
712
			$message = $email_data['gv-note-content'];
713
			$from_name     = $current_user->display_name;
714
			$message_format = 'html';
715
716
			/**
717
			 * @filter `gravityview/field/notes/email_content` Modify the values passed when sending a note email
718
			 * @see GVCommon::send_email
719
			 * @since 1.17
720
			 * @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'
721
			 */
722
			$email_content = apply_filters( 'gravityview/field/notes/email_content', compact( 'from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'entry' ) );
723
724
			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...
725
726
			GVCommon::send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name, $message_format, '', $entry, false );
727
728
			$form  = isset( $entry['form_id'] ) ? GFAPI::get_form( $entry['form_id'] ) : array();
729
730
			/**
731
			 * @see https://www.gravityhelp.com/documentation/article/10146-2/ It's here for compatibility with Gravity Forms
732
			 */
733
			do_action( 'gform_post_send_entry_note', __METHOD__, $to, $from, $subject, $message, $form, $entry );
734
		}
735
	}
736
}
737
738
new GravityView_Field_Notes;
739