PluginProbe
Awesome Support – WordPress HelpDesk & Support Plugin / trunk
Awesome Support – WordPress HelpDesk & Support Plugin vtrunk
6.4.0 trunk 3.0.0 3.0.1 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 All 95 releases
awesome-support / includes / admin / functions-post.php

functions-post.php in Awesome Support – WordPress HelpDesk & Support Plugin trunk, at includes/admin/functions-post.php

827 lines 21.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Awesome Support/Admin/Functions/Post
4 * @author AwesomeSupport <contact@getawesomesupport.com>
5 * @license GPL-2.0+
6 * @link https://getawesomesupport.com
7 * @copyright 2015-2017 AwesomeSupport
8 */
9
10 // If this file is called directly, abort.
11 if ( ! defined( 'WPINC' ) ) {
12 die;
13 }
14
15 add_filter( 'wp_insert_post_data', 'wpas_filter_ticket_data', 99, 2 );
16 /**
17 * Filter ticket data before insertion.
18 *
19 * Before inserting a new ticket in the database,
20 * we check the post status and possibly overwrite it
21 * with one of the registered custom status.
22 *
23 * @since 3.0.0
24 *
25 * @param array $data Post data
26 * @param array $postarr Original post data
27 *
28 * @return array Modified post data for insertion
29 */
30 function wpas_filter_ticket_data( $data, $postarr ) {
31
32 global $current_user;
33
34 if ( ! isset( $data['post_type'] ) || 'ticket' !== $data['post_type'] ) {
35 return $data;
36 }
37
38 /**
39 * If the ticket is being trashed we don't do anything.
40 */
41 if ( 'trash' === $data['post_status'] ) {
42 return $data;
43 }
44
45 /**
46 * Do not affect auto drafts
47 */
48 if ( 'auto-draft' === $data['post_status'] ) {
49 return $data;
50 }
51
52 /**
53 * Sanitize the title of the ticket post
54 */
55 $data['post_title'] = wp_kses_post( $data['post_title'] );
56 $data['post_title'] = sanitize_text_field( $data['post_title'] );
57
58 /* Sanitize the data */
59 $data['post_content'] = wp_kses( $data['post_content'], wp_kses_allowed_html( 'post' ) );
60
61 /**
62 * Automatically set the ticket as processing if this is the first reply.
63 */
64 if ( user_can( $current_user->ID, 'edit_ticket' ) && isset( $postarr['ID'] ) ) {
65
66
67 // @TODO: Its possible that this entire section of code to set the $agent_replied flag might not be needed.
68 // We'll keep it for now but its not used in this function at this time.
69 $replies = wpas_get_replies( intval( $postarr['ID'] ) );
70 $agent_replied = false;
71
72 if ( 0 !== count( $replies ) ) {
73
74 foreach ( $replies as $reply ) {
75 if ( user_can( $reply->post_author, 'edit_ticket' ) ) {
76 $agent_replied = true;
77 break;
78 }
79 }
80
81 }
82
83 // @TODO: Its possible this if statement below might need an additional qualifier to see if $agent_replied = true.
84 // For now, tickets move to "IN PROCESS" correctly. If issues arise, see reference 6655750.
85 $turn_auto_change_status = (bool) wpas_get_option('turn_auto_change_status', true);
86
87 // Get old/new authors (ticket owners)
88 $old_author = (int) get_post_field('post_author', $postarr['ID'], 'raw');
89 $new_author = isset($_POST['post_author']) ? (int) sanitize_text_field($_POST['post_author']) : 0;
90
91 $ticket_id = isset( $postarr['ID'] ) ? (int) $postarr['ID'] : 0;
92 $old_assignee = $ticket_id ? (int) get_post_meta( $ticket_id, '_wpas_assignee', true ) : 0;
93 $new_assignee = isset($_POST['wpas_assignee']) ? (int) sanitize_text_field($_POST['wpas_assignee']) : 0;
94
95 // Detect changes
96 $author_changed = ($new_author !== $old_author);
97 $assignee_changed = ($new_assignee !== $old_assignee);
98
99 // Helper: apply default "processing" status
100 $maybe_set_processing = function () {
101 if (!isset($_POST['post_status_override']) || $_POST['post_status_override'] === 'queued') {
102 $_POST['post_status_override'] = 'processing';
103 }
104 };
105
106 if ($turn_auto_change_status) {
107 // Auto status change enabled
108 $maybe_set_processing();
109 } else {
110 // Auto status change disabled
111 if (!$author_changed && !$assignee_changed) {
112 // Only apply if it's not an assignment or ownership change
113 $maybe_set_processing();
114 }
115 }
116
117 }
118
119 if ( isset( $_POST['post_status_override'] ) && ! empty( $_POST['post_status_override'] ) ) {
120
121 $status = wpas_get_post_status();
122
123 if ( array_key_exists( sanitize_text_field( wp_unslash( $_POST['post_status_override'] ) ), $status ) ) {
124
125 $data['post_status'] = sanitize_text_field( wp_unslash( $_POST['post_status_override'] ) );
126
127 // translators: %s is the state of the ticket
128 $x_content = __( 'Ticket state changed to %s', 'awesome-support' );
129 if ( isset($postarr['original_post_status']) && $postarr['original_post_status'] !== $_POST['post_status_override'] && isset( $_POST['wpas_post_parent'] ) ) {
130 wpas_log_history( intval( $_POST['wpas_post_parent'] ), sprintf( $x_content, '&laquo;' . $status[ sanitize_text_field( wp_unslash( $_POST['post_status_override'] ) ) ] . '&raquo;' ) );
131 }
132 }
133
134 }
135
136 return $data;
137 }
138
139 add_action( 'save_post_ticket', 'wpas_save_ticket' );
140 /**
141 * Save ticket custom fields.
142 *
143 * This function will save all custom fields associated
144 * to the ticket post type. Be it core custom fields
145 * or user added custom fields.
146 *
147 * @param (int) $post_id Current post ID
148 *
149 * @since 3.0.0
150 */
151 function wpas_save_ticket( $post_id ) {
152
153 /* We should already being avoiding Ajax, but let's make sure */
154 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_id ) ) {
155 return;
156 }
157
158 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
159 return;
160 }
161
162 /* Now we check the nonce */
163 if ( ! isset( $_POST['wpas_cf'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wpas_cf'] ) ), 'wpas_update_cf' ) ) {
164 return;
165 }
166
167 /* Does the current user have permission? */
168 if ( ! current_user_can( 'edit_ticket', $post_id ) ) {
169 return;
170 }
171
172 global $current_user;
173
174 /**
175 * Store possible logs
176 */
177 $log = array();
178
179 /**
180 * Save old assignee - will need to pass it to action hooks later
181 */
182 $old_assignee = get_post_meta( $post_id, '_wpas_assignee', true );
183
184 /* Now we can save the custom fields */
185 WPAS()->custom_fields->save_custom_fields( $post_id, $_POST );
186
187 /**
188 * If no ticket status is found we are in the situation where
189 * the agent is creating a ticket on behalf of the user. There are
190 * a couple of things that we need to do then.
191 */
192 if ( '' === $original_status = get_post_meta( $post_id, '_wpas_status', true ) ) {
193
194 /**
195 * First of all, set the ticket as open. This is very important.
196 */
197 add_post_meta( $post_id, '_wpas_status', 'open', true );
198
199 /* Next - update other some meta values. If you add or delete from this list you also */
200 /* need to do the same thing in the /includes/functions-post.php file */
201 add_post_meta( $post_id, '_wpas_last_reply_date', null, true );
202 add_post_meta( $post_id, '_wpas_last_reply_date_gmt', null, true );
203
204 /* Set the slug */
205 wpas_set_ticket_slug( $post_id );
206
207 /**
208 * Fire hook when a new ticket is being added - works great for notifications
209 *
210 * @since 4.0.0
211 *
212 * @param int $post_id Ticket ID
213 */
214 do_action( 'wpas_post_new_ticket_admin', $post_id );
215
216 }
217
218 /* Save the possible ticket reply */
219 if ( ! wpas_is_new_reply_empty( $post_id ) ) {
220
221 $ticket_reply = isset($_POST['wpas_reply_ticket']) ? sanitize_text_field( wp_unslash( $_POST['wpas_reply_ticket'] ) ) : null ;
222
223 /* Check for the nonce */
224 if ( wp_verify_nonce( $ticket_reply, 'reply_ticket' ) ) {
225
226 $user_id = $current_user->ID;
227 $content = isset( $_POST['wpas_reply'] ) ? wp_kses_post( $_POST['wpas_reply'] ) : '';
228
229
230 $data = apply_filters( 'wpas_post_reply_admin_args', array(
231 'post_content' => $content,
232 'post_status' => 'read',
233 'post_type' => 'ticket_reply',
234 'post_author' => $user_id,
235 'post_parent' => $post_id,
236 'ping_status' => 'closed',
237 'comment_status' => 'closed',
238 ) );
239
240 /**
241 * Remove the save_post hook now as we're going to trigger
242 * a new one by inserting the reply (and logging the history later).
243 */
244 remove_action( 'save_post_ticket', 'wpas_save_ticket' );
245
246 /**
247 * Fires right before a ticket reply is submitted
248 *
249 * @since 3.2.6
250 *
251 * @param int $post_id Ticket ID
252 * @param array $data Data to be inserted as the reply
253 */
254 do_action( 'wpas_post_reply_admin_before', $post_id, $data );
255
256 /* Insert the reply in DB */
257 $reply = wpas_add_reply( $data, $post_id );
258
259 /**
260 * Fires right after a ticket reply is submitted
261 *
262 * @since 3.2.6
263 *
264 * @param int $post_id Ticket ID
265 * @param array $data Data to be inserted as the reply
266 * @param bool|int Reply ID on success, false on failure
267 */
268 do_action( 'wpas_post_reply_admin_after', $post_id, $data, $reply );
269
270 /* In case the insertion failed... */
271 if ( is_wp_error( $reply ) ) {
272
273 // Fire action hook for failed reply inserted via admin
274 do_action( 'wpas_insert_reply_admin_failed', $post_id, $data, $reply );
275
276 /* Set the redirection */
277 $_SESSION['wpas_redirect'] = add_query_arg( array( 'wpas-message' => 'wpas_reply_error' ), get_permalink( $post_id ) );
278
279 } else {
280
281 /**
282 * Fire action hook for reply inserted via admin - great place for notifications...
283 */
284 do_action( 'wpas_insert_reply_admin_success', $post_id, $data, $reply );
285
286 /* The agent wants to close the ticket */
287 if ( isset( $_POST['wpas_do'] ) && 'reply_close' == $_POST['wpas_do'] ) {
288
289 /* Confirm the post type and close */
290 if ( 'ticket' == get_post_type( $post_id ) ) {
291
292 /**
293 * wpas_ticket_before_close_by_agent hook
294 */
295 do_action( 'wpas_ticket_before_close_by_agent', $post_id );
296
297 /* Close */
298 $closed = wpas_close_ticket( $post_id );
299
300 /**
301 * wpas_ticket_closed_by_agent hook
302 */
303
304 if( $closed ) {
305 do_action( 'wpas_ticket_closed_by_agent', $post_id );
306 }
307 }
308
309 }
310
311 }
312
313 }
314
315 }
316
317 /* Log the action */
318 if ( ! empty( $log ) ) {
319 wpas_log_history( $post_id, $log );
320 }
321
322 /* If this was a ticket update, we need to fire some action hooks and then figure out where to go next... */
323 if ( '' !== $original_status ) {
324
325 /**
326 * Fire action hook for after ticket update...
327 *
328 * @since 4.0.0
329 */
330 do_action( 'wpas_ticket_after_update_admin_success', $post_id, $old_assignee, $_POST);
331
332 $gt_post = null;
333 $where_after = isset( $_POST['where_after'] ) ? sanitize_text_field( wp_unslash( $_POST['where_after'] ) ) : '';
334 $back_to_list = filter_input( INPUT_POST, 'wpas_back_to_list', FILTER_SANITIZE_NUMBER_INT );
335
336 if ( true === (bool) $back_to_list ) {
337 $where_after = 'back_to_list';
338 }
339
340 switch ( $where_after ) {
341
342 /* Go back to the tickets list */
343 case 'back_to_list':
344 WPAS()->session->add( 'redirect', add_query_arg( array( 'post_type' => 'ticket' ), admin_url( 'edit.php' ) ) );
345 break;
346
347 case 'next_ticket':
348 $gt_post = wpas_get_next_ticket( $post_id );
349 break;
350
351 case 'previous_ticket':
352 $gt_post = wpas_get_previous_ticket( $post_id );
353 break;
354
355 }
356
357 /* Go to next or previous ticket */
358 if ( $gt_post ) {
359 WPAS()->session->add( 'redirect', add_query_arg( array(
360 'post' => $gt_post,
361 'action' => 'edit',
362 ), admin_url( 'post.php' ) ) );
363 }
364 }
365
366 do_action( 'wpas_ticket_after_saved', $post_id );
367 wpas_admin_clean_ticketcount_cache( $post_id );
368 }
369
370 add_action( 'wpas_add_reply_after', 'wpas_mark_replies_read', 10, 2 );
371 /**
372 * Mark replies as read.
373 *
374 * When an agent replies to a ticket, we mark all previous replies
375 * as read. We suppose it's all been read when the agent replies.
376 * This allows for keeping replies unread until an agent replies
377 * or manually marks the last reply as read.
378 *
379 * @since 3.0.0
380 *
381 * @param $reply_id
382 * @param $data
383 *
384 * @return void
385 */
386 function wpas_mark_replies_read( $reply_id, $data ) {
387
388 $replies = wpas_get_replies( intval( $data['post_parent'] ), 'unread' );
389
390 foreach ( $replies as $reply ) {
391 wpas_mark_reply_read( $reply->ID );
392 }
393
394 }
395
396 add_action( 'before_delete_post', 'wpas_delete_ticket_dependencies', 10, 1 );
397 /**
398 * Delete ticket dependencies.
399 *
400 * Delete all ticket dependencies when a ticket is deleted. This includes
401 * ticket replies and ticket history. Ticket attachments are deleted by
402 * WPAS_File_Upload::delete_attachments()
403 *
404 * @param integer $post_id ID of the post to be deleted
405 *
406 * @return void
407 */
408 function wpas_delete_ticket_dependencies( $post_id ) {
409
410 global $post_type;
411
412 if ( 'ticket' !== $post_type ) {
413 return;
414 }
415
416 /* First of all we remove this action to avoid creating a loop */
417 remove_action( 'before_delete_post', 'wpas_delete_ticket_dependencies', 10 );
418
419 $args = array(
420 'post_parent' => $post_id,
421 'post_type' => apply_filters( 'wpas_replies_post_type', array(
422 'ticket_history',
423 'ticket_reply',
424 'ticket_log'
425 ) ),
426 'post_status' => 'any',
427 'posts_per_page' => - 1,
428 'no_found_rows' => true,
429 'cache_results' => false,
430 'update_post_term_cache' => false,
431 'update_post_meta_cache' => false,
432 );
433
434 $posts = new WP_Query( $args );
435
436 foreach ( $posts->posts as $id => $post ) {
437
438 do_action( 'wpas_before_delete_dependency', $post->ID, $post );
439
440 wp_delete_post( $post->ID, true );
441
442 do_action( 'wpas_after_delete_dependency', $post->ID, $post );
443 }
444
445 /* Decrement the number of tickets open for this agent */
446 $agent_id = get_post_meta( $post_id, '_wpas_assignee', true );
447 $agent = new WPAS_Member_Agent( $agent_id );
448 $agent->ticket_minus();
449
450 }
451
452
453 add_filter( 'redirect_post_location', 'wpas_redirect_ticket_after_save', 10, 2 );
454
455 /**
456 * Redirect user after updating ticket
457 *
458 * @param string $location The redirect URL.
459 * @param int $post_id ID of the post being saved.
460 *
461 * @return string
462 */
463 function wpas_redirect_ticket_after_save( $location, $post_id ) {
464 if ( is_admin() ) {
465
466 $post = get_post( $post_id );
467
468 if ( $post && 'ticket' === $post->post_type ) {
469
470 // Get the redirect location.
471 $redirect = WPAS()->session->get( 'redirect' );
472
473 if ( false !== $redirect && filter_var( $redirect, FILTER_VALIDATE_URL ) !== false ) {
474 $location = $redirect;
475 WPAS()->session->clean( 'redirect' );
476 }
477 }
478 }
479
480 return $location;
481
482 }
483
484 /**
485 * Get next id
486 * @param int $current_ticket
487 *
488 * @return int
489 */
490 function wpas_get_next_ticket( $current_ticket ) {
491
492 return wpas_get_adjacent_ticket( $current_ticket );
493
494 }
495
496 /**
497 * Get previous id
498 * @param int $current_ticket
499 *
500 * @return int
501 */
502 function wpas_get_previous_ticket( $current_ticket ) {
503
504 return wpas_get_adjacent_ticket( $current_ticket, false );
505
506 }
507
508
509 /**
510 *
511 * @global object $wpdb
512 * @global object $current_user
513 * @param int $ticket_id
514 * @param boolean $next
515 *
516 * @return int
517 */
518 function wpas_get_adjacent_ticket( $ticket_id , $next = true ) {
519
520 /* Make sure this is the admin screen */
521 if ( ! is_admin() ) {
522 return false;
523 }
524
525 if ( true === $next ) {
526 $adjacent = '>';
527 $order_type = 'ASC';
528 } else {
529 $adjacent = '<';
530 $order_type = 'DESC';
531 }
532
533 $custom_post_status = wpas_get_post_status();
534 $custom_post_status['open'] = 'Open';
535
536 $meta_query = wpas_ticket_listing_assignee_meta_query_args();
537
538 $args = array(
539 'post_type' => 'ticket',
540 'posts_per_page' => 1,
541 'orderby' => 'ID',
542 'order' => $order_type,
543 'post_status' => array_keys( $custom_post_status ),
544 'meta_query' => $meta_query,
545 'next_previous_adjacent' => "{$adjacent} {$ticket_id}",
546 'wpas_tickets_query' => 'listing'
547 );
548
549 $query = new WP_Query( $args );
550
551 $adjacent_post_id = '';
552
553 if ( !empty( $query->posts ) ) {
554 $adjacent_post_id = $query->posts[0]->ID;
555 }
556
557 return $adjacent_post_id;
558 }
559
560 add_filter( 'posts_clauses', 'wpas_get_adjacent_ticket_posts_clauses', 30, 2 );
561
562 /**
563 * Modify get_adjacent_ticket query
564 *
565 * @global object $wpdb
566 * @param array $pieces
567 * @param object $wp_query
568 *
569 * @return array
570 */
571 function wpas_get_adjacent_ticket_posts_clauses( $pieces , $wp_query ) {
572 global $wpdb;
573
574 if ( isset( $wp_query->query['next_previous_adjacent'] ) ) {
575 $adjacent = $wp_query->query['next_previous_adjacent'];
576 $pieces['where'] = "AND ({$wpdb->posts}.ID {$adjacent} ) " . $pieces['where'];
577 }
578
579 return $pieces;
580 }
581
582 /**
583 *
584 * @param array $args
585 * @param string $ticket_status
586 *
587 * @return array|int
588 */
589 function wpas_get_agent_tickets( $args = array(), $ticket_status = 'any' ) {
590
591 global $current_user;
592
593 $custom_post_status = wpas_get_post_status();
594 $custom_post_status['open'] = 'Open';
595
596 foreach($custom_post_status as $status => $label) {
597 $post_status[] = $status;
598 }
599
600
601 $defaults = array(
602 'post_type' => 'ticket',
603 'post_status' => $post_status,
604 'posts_per_page' => - 1
605 );
606
607 $args = wp_parse_args( $args, $defaults );
608
609 $meta_query = array();
610
611 if ( 'any' !== $ticket_status ) {
612 if ( in_array( $ticket_status, array( 'open', 'closed' ) ) ) {
613 $meta_query[] = array(
614 'key' => '_wpas_status',
615 'value' => $ticket_status,
616 'compare' => '=',
617 'type' => 'CHAR'
618 );
619 }
620 }
621
622
623
624 $meta_query = wpas_ticket_listing_assignee_meta_query_args();
625
626 if( !empty( $meta_query ) ) {
627 $args['meta_query'] = $meta_query;
628 }
629
630 $args['wpas_tickets_query'] = 'listing';
631
632 $query = new WP_Query( $args );
633 if ( empty( $query->posts ) ) {
634 return array();
635 } else {
636 return $query->posts;
637 }
638
639 }
640
641 /**
642 * Return meta query args for ticket listing query relative to assignee
643 *
644 * @param type $use_id
645 * @return type
646 */
647 function wpas_ticket_listing_assignee_meta_query_args( $user_id = 0, $profile_filter = true ) {
648
649 if( 0 === $user_id ) {
650 $user_id = get_current_user_id();
651 }
652
653 $user_can_see_all = wpas_can_user_see_all_tickets();
654
655 $meta_query = array();
656
657 if( false === $user_can_see_all ) {
658
659 $primary_agent_meta_query = array(
660 'key' => '_wpas_assignee',
661 'value' => (int) $user_id,
662 'compare' => '=',
663 'type' => 'NUMERIC',
664 );
665
666 if( wpas_is_multi_agent_active() ) {
667 // Check if agent is set as secondary or tertiary agent
668 $multi_agents_meta_query = array();
669 $multi_agents_meta_query['relation'] = 'OR';
670 $multi_agents_meta_query[] = $primary_agent_meta_query;
671
672 $multi_agents_meta_query[] = array(
673 'key' => '_wpas_secondary_assignee',
674 'value' => (int) $user_id,
675 'compare' => '=',
676 'type' => 'NUMERIC',
677 );
678
679 $multi_agents_meta_query[] = array(
680 'key' => '_wpas_tertiary_assignee',
681 'value' => (int) $user_id,
682 'compare' => '=',
683 'type' => 'NUMERIC',
684 );
685
686 $meta_query[] = $multi_agents_meta_query;
687
688 } else {
689 $meta_query[] = $primary_agent_meta_query;
690 }
691 }
692
693 return apply_filters( 'wpas_assignee_meta_query', $meta_query, $user_id, $profile_filter );
694
695 }
696
697
698 /**
699 * Generate a link with icon for a reply action
700 *
701 * @param string $id
702 * @param array $args
703 *
704 * @return string
705 */
706 function wpas_reply_control_item( $id , $args = array() ) {
707
708 $link = isset( $args['link'] ) ? $args['link'] : '#';
709 $title = isset( $args['title'] ) ? $args['title'] : '';
710
711 $icon = isset( $args['icon'] ) && $args['icon'] ? $args['icon'] : false;
712
713 $attr_id = isset( $args['id'] ) && $args['id'] ? $args['id'] : '';
714
715 $classes = isset( $args['classes'] ) ? $args['classes'] : '';
716 $classes .= " {$id}";
717 $classes .= ( $icon ? ' reply_icon' : '' );
718 $classes .= $title ? ' hint-bottom hint-anim' : '';
719
720 $data_params = isset( $args['data'] ) && is_array( $args['data'] ) ? $args['data'] : array();
721
722 $markup = "<a href=\"{$link}\" data-hint=\"{$title}\" class=\"{$classes}\"";
723
724 foreach( $data_params as $dp_name => $dp_value ) {
725 $markup .= " data-{$dp_name}=\"{$dp_value}\"";
726 }
727
728 $markup .= $attr_id ? " id=\"{$attr_id}\"" : '';
729 $markup .= '>';
730 $markup .= $icon ? "<img src=\"{$icon}\" />" : '';
731 $markup .= '</a>';
732
733
734 return $markup;
735 }
736
737
738 /**
739 * Check if reply content or attachments provided with new reply
740 */
741 function wpas_is_new_reply_empty( $ticket_id ) {
742
743 $content_empty = isset( $_POST['wpas_reply'] ) && isset( $_POST['wpas_reply_ticket'] ) && '' !== $_POST['wpas_reply'] ? false : true;
744
745 $attachments_empty = true;
746
747 // Check if agent uploaded attachments
748 if( $content_empty ) {
749
750 if ( boolval( wpas_get_option( 'ajax_upload', false ) ) || boolval( wpas_get_option( 'ajax_upload_all', false ) ) ) {
751
752 $upload = wp_upload_dir();
753 $dir = trailingslashit( $upload['basedir'] ) . 'awesome-support/temp_' . $ticket_id . '_' . get_current_user_id() .'/';
754
755 // If temp directory exists, it means that user is uploaded attachments
756 if ( is_dir( $dir ) ) {
757
758 $filetypes = explode( ',', apply_filters( 'wpas_attachments_filetypes', wpas_get_option( 'attachments_filetypes' ) ) );
759 $accept = array();
760
761 foreach ( $filetypes as $key => $type ) {
762 array_push( $accept, '*.' . $type );
763 array_push( $accept, '*.' . strtoupper( $type ) );
764 }
765
766 $accept = implode( ',', $accept );
767
768
769 $files = glob( $dir . '{' . $accept . '}', GLOB_BRACE );
770 $attachments_empty = empty( $files ) ? true : false;
771 }
772
773
774 } else {
775 $attachments_empty = $_FILES && isset( $_FILES['wpas_files'] ) && !empty( $_FILES['wpas_files']['name'][0] ) ? false : true;
776 }
777
778 }
779
780 return ( $content_empty && $attachments_empty );
781 }
782
783 add_action( 'wpas_backend_ticket_status_before_actions', 'wpas_close_ticket_prevent_client_notification_field', 12 );
784 /**
785 * Add Checkbox to prevent client notification about ticket close
786 *
787 * @param int $ticket_id
788 */
789 function wpas_close_ticket_prevent_client_notification_field( $ticket_id ) {
790
791 /* Do not show the checkbox if not enabled in settings */
792 if ( ! boolval( wpas_get_option( 'agents_can_suppress_closing_emails', false ) ) ) {
793 return ;
794 }
795
796 $close_ticket_prevent_client_notification = get_post_meta( $ticket_id, 'wpas_close_ticket_prevent_client_notification', true );
797 ?>
798
799 <div>
800 <p>
801 <label>
802 <input type="checkbox" value="1" data-nonce="<?php echo esc_attr( wp_create_nonce( 'prevent_client_notification' ) ); ?>" name="close_ticket_prevent_client_notification" <?php checked( '1', $close_ticket_prevent_client_notification); ?> />
803 <?php esc_html_e( 'Do NOT send closing ticket email to customer', 'awesome-support' ); ?>
804 </label>
805 </p>
806 </div>
807 <?php
808 }
809
810 add_action( 'trashed_post', 'wpas_admin_clean_ticketcount_cache' );
811 add_action( 'untrashed_post', 'wpas_admin_clean_ticketcount_cache' );
812 /**
813 * Delete ticket count cache on ticket update
814 *
815 * @param int $ticket_id
816 */
817 function wpas_admin_clean_ticketcount_cache( $ticket_id = '' )
818 {
819 $post = get_post( $ticket_id );
820
821 if (isset( $post ) && isset( $post->post_type) && $post->post_type !== 'ticket') {
822 return;
823 }
824 set_site_transient( 'wpas_tickets_counts', null, 24 * HOUR_IN_SECONDS );
825 }
826
827