Completed
Push — develop ( 84f0d3...502ca6 )
by Zack
17:40 queued 13:10
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 2
Bugs 0 Features 1
Metric Value
cc 3
eloc 15
c 2
b 0
f 1
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 737.

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