1
|
|
|
<?php |
|
|
|
|
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; |
|
|
|
|
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var string plugin_dir_path() of the current field file |
27
|
|
|
* @since 1.17 |
28
|
|
|
*/ |
29
|
|
|
static $path; |
|
|
|
|
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'; |
|
|
|
|
42
|
|
|
|
43
|
|
|
function __construct() { |
|
|
|
|
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 ); |
|
|
|
|
67
|
|
|
add_action( 'wp_ajax_nopriv_gv_delete_notes', array( $this, 'maybe_delete_notes') ); |
|
|
|
|
68
|
|
|
add_action( 'wp_ajax_gv_delete_notes', array( $this, 'maybe_delete_notes') ); |
|
|
|
|
69
|
|
|
|
70
|
|
|
add_action( 'wp', array( $this, 'maybe_add_note'), 1000 ); |
|
|
|
|
71
|
|
|
add_action( 'wp_ajax_nopriv_gv_note_add', array( $this, 'maybe_add_note') ); |
|
|
|
|
72
|
|
|
add_action( 'wp_ajax_gv_note_add', array( $this, 'maybe_add_note') ); |
|
|
|
|
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') ); |
|
|
|
|
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 ); |
|
|
|
|
121
|
|
|
wp_register_script( 'gravityview-notes', plugins_url( '/assets/js/entry-notes.js', GravityView_Field_Notes::$file ), array( 'jquery' ), GravityView_Plugin::version, true ); |
|
|
|
|
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; |
|
|
|
|
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() { |
|
|
|
|
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'] ) ) { |
|
|
|
|
173
|
|
|
return; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if( 'gv_note_add' === $_POST['action'] ) { |
|
|
|
|
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 ); |
|
|
|
|
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'); |
|
|
|
|
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'); |
|
|
|
|
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'); |
|
|
|
|
261
|
|
|
gravityview()->log->error( 'Nonce validation failed; the note was not created' ); |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
266
|
|
|
if( $this->doing_ajax ) { |
267
|
|
|
if( $success ) { |
|
|
|
|
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() { |
|
|
|
|
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 ); |
|
|
|
|
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 ) { |
|
|
|
|
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; |
|
|
|
|
365
|
54 |
|
$file_paths[ 173 ] = self::$path . 'partials/'; |
|
|
|
|
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'), |
|
|
|
|
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>' ), |
|
|
|
|
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 = '' ) { |
|
|
|
|
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…', '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'), |
|
|
|
|
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 ) { |
|
|
|
|
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 |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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}"] ) ) { |
|
|
|
|
656
|
|
|
$note_emails[] = $entry["{$email_field->id}"]; |
|
|
|
|
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> |
|
|
|
|
707
|
|
|
<select class="gv-note-email-to" name="gv-note-to" id="gv-note-email-to-<?php echo $entry_slug_esc; ?>"> |
|
|
|
|
708
|
|
|
<option value=""><?php echo $strings['also-email']; ?></option> |
|
|
|
|
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> |
|
|
|
|
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> |
|
|
|
|
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="" /> |
|
|
|
|
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> |
|
|
|
|
726
|
|
|
<input type="text" name="gv-note-subject" placeholder="<?php echo $strings['subject']; ?>" id="gv-note-subject-<?php echo $entry_slug_esc; ?>" value="" /> |
|
|
|
|
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') ) { |
|
|
|
|
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(); |
|
|
|
|
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 ) ); |
|
|
|
|
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 ); |
|
|
|
|
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
|
|
|
|
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.