public function action_wp_ajax_supportflow_json() { $response = array('api-action' => !empty($_REQUEST['api-action']) ? sanitize_key($_REQUEST['api-action']) : '', 'status' => 'error', 'message' => '', 'html' => ''); switch ($response['api-action']) { case 'get-customers': check_ajax_referer('get_customers', 'get_customers_nonce'); if (current_user_can('sf_get_customers')) { $search_for = sanitize_text_field(isset($_REQUEST['customers']) ? $_REQUEST['customers'] : ''); $customer_matches = SupportFlow()->get_customers(array('search' => $search_for)); } else { $customer_matches = new WP_Error('sf_access_denied', __('Access denied.', 'supportflow')); } if (is_wp_error($customer_matches)) { $response['message'] = $customer_matches->get_error_message(); } else { $response['query'] = $search_for; $response['status'] = "ok"; $response['customers'] = $customer_matches; } break; default: $response['message'] = __("There's no API method registered under that action.", 'supportflow'); break; } $response = apply_filters('supportflow_json_api_response', $response); @header('Content-Type: application/json; charset=' . get_option('blog_charset')); echo json_encode($response); die; }
/** * Add predefined options under Supportflow menu */ public function action_admin_menu_predefined_replies() { $post_type = SupportFlow()->post_type; $predefinded_replies_type = SupportFlow()->predefinded_replies_type; add_submenu_page("edit.php?post_type={$post_type}", 'All predefined replies', 'All predefined replies', 'manage_options', "edit.php?post_type={$predefinded_replies_type}"); add_submenu_page("edit.php?post_type={$post_type}", 'New predefined reply', 'New predefined reply', 'manage_options', "post-new.php?post_type={$predefinded_replies_type}"); }
public function get_attachment_id($attachment_secret) { $post_statuses = SupportFlow()->post_statuses; $posts = get_posts(array('post_type' => 'attachment', 'post_status' => 'inherit', 'meta_query' => array(array('key' => 'sf_attachment_secret', 'value' => $attachment_secret)))); if (isset($posts[0])) { return $posts[0]->ID; } else { return 0; } }
/** * Setup globals that require some of the other classes to be loaded */ protected function setup_late_globals() { /* * Gmail might block access if a client checks more than every 10 minutes. * https://support.google.com/mail/answer/14257?p=client_login&rd=1 */ $this->cron_interval = SupportFlow()->extend->email_accounts->has_gmail_account() ? 10 * MINUTE_IN_SECONDS : 5 * MINUTE_IN_SECONDS; $this->cron_interval = apply_filters('supportflow_cron_interval', $this->cron_interval); }
public function action_template_redirect() { global $current_user; wp_enqueue_script($this->script_slug, plugins_url('js/supportflow-user-widget.js', dirname(__FILE__)), array('jquery'), mt_rand()); $ajaxurl = add_query_arg('action', SupportFlow()->extend->jsonapi->action, admin_url('admin-ajax.php')); $widget_title = __('Support', 'supportflow'); $start_ticket_text = __('Start ticket', 'supportflow'); $starting_ticket_text = __('Starting ticket...', 'supportflow'); $send_reply_text = __('Send reply', 'supportflow'); $sending_reply_text = __('Sending reply...', 'supportflow'); wp_localize_script($this->script_slug, 'SupportFlowUserWidgetVars', array('ajaxurl' => $ajaxurl, 'widget_title' => $widget_title, 'start_ticket_text' => $start_ticket_text, 'starting_ticket_text' => $starting_ticket_text, 'send_reply_text' => $send_reply_text, 'sending_reply_text' => $sending_reply_text)); wp_enqueue_style($this->script_slug, plugins_url('css/widget.css', dirname(__FILE__)), array(), mt_rand()); ?> <html> <head> <title><?php _e('Support', 'supportflow'); ?> </title> <?php wp_head(); ?> </head> <body> <div id="supportflow-widget"> <button id="supportflow-back"><?php _e('All Tickets', 'supportflow'); ?> </button> <h1 id="widget-title"><?php echo $widget_title; ?> </h1> <div id="supportflow-newticket-box"> <button id="supportflow-newticket"><?php _e('Start a new ticket', 'supportflow'); ?> </button> <form id="supportflow-newticket-form"> <input type="text" id="new-ticket-subject" name="new-ticket-subject" class="ticket-subject" placeholder="<?php esc_attr_e('What can we help with?', 'supportflow'); ?> " autocomplete="off" /> <textarea id="new-ticket-message" name="new-ticket-message" class="ticket-message" cols="25" rows="6" placeholder="<?php esc_attr_e('Tell us a bit more...', 'supportflow'); ?> " autocomplete="off"></textarea> <input id="new-ticket-submit" type="submit" name="new-ticket-submit" class="submit-button" value="<?php echo esc_attr($start_ticket_text); ?> " /> </form> </div> <div id="supportflow-all-tickets"> <?php echo $this->render_all_tickets_html(); ?> </div> <div id="supportflow-single-ticket"> <div id="supportflow-ticket-body"> </div> <form id="supportflow-existing-ticket-form"> <textarea id="existing-ticket-message" name="existing-ticket-message" class="ticket-message" cols="25" rows="6" autocomplete="off"></textarea> <input id="existing-ticket-submit" type="submit" name="existing-ticket-submit" class="submit-button" value="<?php echo esc_attr($send_reply_text); ?> " /> <input id="existing-ticket-id" name="ticket-id" type="hidden" /> </form> </div> </div> </body> </html> <?php exit; }
public function is_user_allowed_post($user_id, $post_id) { $user_permissions = $this->get_user_permissions_data($user_id); $post_email_account = get_post_meta($post_id, 'email_account', true); $post_tags = wp_get_post_terms($post_id, SupportFlow()->tags_tax); if (in_array($post_email_account, $user_permissions['email_accounts'])) { return true; } foreach ($post_tags as $post_tag) { $post_tag_slug = $post_tag->slug; if (in_array($post_tag_slug, $user_permissions['tags'])) { return true; } } return false; }
public function action_init_handle_form_submission() { if (!isset($_POST['action'], $_POST['_wpnonce']) || !'sf_create_ticket' == $_POST['action'] || !wp_verify_nonce($_POST['_wpnonce'], '_sf_create_ticket')) { return; } if (empty($_POST['fullname'])) { $this->messages[] = __('The name field is required.', 'supportflow'); } if (empty($_POST['email'])) { $this->messages[] = __('The email field is required.', 'supportflow'); } elseif (!is_email($_POST['email'])) { $this->messages[] = __('Please enter a valid e-mail address.', 'supportflow'); } if (empty($_POST['subject'])) { $this->messages[] = __('The subject field is required.', 'supportflow'); } if (empty($_POST['message'])) { $this->messages[] = __('You must enter a message.', 'supportflow'); } if (!empty($this->messages)) { return; } // Load required file require_once SupportFlow()->plugin_dir . 'classes/class-supportflow-admin.php'; $ticket_id = SupportFlow()->create_ticket(array('subject' => $_POST['subject'], 'message' => $_POST['message'], 'reply_author' => $_POST['fullname'], 'reply_author_email' => $_POST['email'], 'customer_email' => array($_POST['email']))); if (is_wp_error($ticket_id)) { $this->messages[] = __('There is an unknown error while submitting the form. Please try again later.', 'supportflow'); return; } $this->messages[] = __('Form submitted successfully', 'supportflow'); }
function action_sf_my_tickets() { $statuses = SupportFlow()->post_statuses; $status_slugs = array(); foreach ($statuses as $status => $status_data) { if (true == $status_data['show_tickets']) { $status_slugs[] = $status; } } $table = new SupportFlow_Table(); $user_id = get_current_user_id(); foreach ($status_slugs as $status_slug) { $args = array('post_type' => SupportFlow()->post_type, 'post_parent' => 0, 'posts_per_page' => 10, 'post_status' => $status_slug, 'author' => $user_id); $wp_query = new WP_Query($args); $tickets = $wp_query->posts; $no_items = '<a href="post-new.php?post_type=' . SupportFlow()->post_type . '">' . __('<b>Click here</b>') . '</a>'; $no_items = sprintf(__('No matching ticket exists. %s to create new.', 'supportflow'), $no_items); $table->set_no_items($no_items); $table->set_columns(array('title' => __('Subject', 'supportflow'), 'modified' => __('Last modified', 'supportflow'), 'datetime' => __('Created', 'supportflow'))); $data = array(); foreach ($tickets as $ticket) { $post_date = strtotime($ticket->post_date); $post_modified = strtotime($ticket->post_modified); $title = '<b>' . esc_html($ticket->post_title) . '</b>'; $title = "<a href='post.php?post=" . $ticket->ID . "&action=edit'>" . $title . "</a>"; $data[] = array('title' => $title, 'modified' => sprintf(__('%s ago', 'supportflow'), human_time_diff(time(), $post_modified)), 'datetime' => sprintf(__('%s ago', 'supportflow'), human_time_diff(time(), $post_date))); } $table->set_data($data); echo '<div class="container">'; echo "<h3 class='toggle-link'>" . $statuses[$status_slug]['label'] . "</h3>"; echo "<div class='toggle-content'>"; $table->display(); echo "</div>"; echo '</div>'; } }
/** * AJAX request to change user E-Mail notification settings */ public function action_wp_ajax_set_email_notfication() { check_ajax_referer('set_email_notfication', '_set_email_notfication_nonce'); if (!isset($_POST['privilege_type']) || !isset($_POST['privilege_id']) || !isset($_POST['allowed']) || !in_array($_POST['privilege_type'], array('email_accounts', 'tags'))) { exit; } $privilege_type = $_POST['privilege_type']; $privilege_id = $_POST['privilege_id']; $allowed = 'true' == $_POST['allowed'] ? true : false; echo SupportFlow()->extend->email_notifications->set_notfication_settings($privilege_type, $privilege_id, $allowed); exit; }
/** * Add a page to display log items * * Disabled by default to avoid cluttering the menu with something that is rarely used */ public function add_admin_menu_items() { if (apply_filters('supportflow_show_log', false)) { add_submenu_page('edit.php?post_type=' . SupportFlow()->post_type, __('Log', 'supportflow'), __('Log', 'supportflow'), 'manage_options', 'log', array($this, 'markup_log_page')); } }
public function get_quoted_text($ticket) { // Insert last second reply as quoted text $replies = SupportFlow()->get_ticket_replies($ticket->ID, array('numberposts' => 2)); if (empty($replies[1])) { return ''; } else { $quoted_reply = $replies[1]; $reply_author = get_post_meta($quoted_reply->ID, 'reply_author', true); if (empty($reply_author)) { $reply_author = get_post_meta($ticket_reply->ID, 'reply_author_email', true); } $time_stamp = $ticket->post_date_gmt; $heading = sprintf("On %s GMT, %s wrote:", $time_stamp, $reply_author); $content = SupportFlow()->sanitize_ticket_reply(stripslashes($quoted_reply->post_content)); $content = "> {$content}"; $content = str_replace("\n", "\n> ", $content); return "{$heading}\n{$content}"; } }
/** * Get the special capability given a string */ public function get_cap($cap) { return SupportFlow()->extend->permissions->get_cap($cap); }
/** * Given an email object, maybe create a new ticket */ public function process_email($imap_connection, $email, $i, $to, $email_account_id) { require_once ABSPATH . 'wp-admin/includes/admin.php'; $new_attachment_ids = array(); $k = 0; if (isset($email->structure->parts)) { foreach ($email->structure->parts as $email_part) { // We should at least be dealing with something that resembles an email object at this point if (!isset($email_part->disposition, $email_part->subtype, $email_part->dparameters[0]->value)) { continue; } if ('ATTACHMENT' == $email_part->disposition) { // We need to add 2 to our array key each time to get the correct email part //@todo this needs more testing with different emails, should be smarter about which parts $raw_attachment_data = imap_fetchbody($imap_connection, $i, $k + 2); // The raw data from imap is base64 encoded, but php-imap has us covered! $attachment_data = imap_base64($raw_attachment_data); $temp_file = get_temp_dir() . time() . '_supportflow_temp.tmp'; touch($temp_file); $temp_handle = fopen($temp_file, 'w+'); fwrite($temp_handle, $attachment_data); fclose($temp_handle); $file_array = array('tmp_name' => $temp_file, 'name' => $email_part->dparameters[0]->value); $upload_result = media_handle_sideload($file_array, null); if (is_wp_error($upload_result)) { WP_CLI::warning($upload_result->get_error_message()); } else { SupportFlow()->extend->attachments->secure_attachment_file($upload_result); $new_attachment_ids[] = $upload_result; } } $k++; } } if (!empty($email->headers->subject)) { $subject = imap_utf8($email->headers->subject); } else { $subject = sprintf(__('New ticket from %s', 'supportflow'), $email->headers->fromaddress); } $reply_author = isset($email->headers->from[0]->personal) ? $email->headers->from[0]->personal : ''; $reply_author_email = $email->headers->from[0]->mailbox . '@' . $email->headers->from[0]->host; // Parse out the reply body if (function_exists('What_The_Email')) { $message = What_The_Email()->get_message($email->body); } else { $message = $email->body; } // Check if this email should be blocked if (function_exists('What_The_Email')) { $check_strings = array('subject' => $subject, 'sender' => $reply_author_email, 'message' => $message); foreach ($check_strings as $key => $value) { if (What_The_Email()->is_robot($key, $value)) { SupportFlow()->extend->logger->log('email_retrieve', __METHOD__, __('Skipping e-mail because sender is a robot.', 'supportflow'), compact('email')); return true; } } } // Check to see if this message was in response to an existing ticket $ticket_id = false; if (preg_match('/#(\\d+):/', $subject, $matches)) { $ticket_id = $matches[1]; $ticket = get_post($ticket_id); // Make sure the ticket ID is a SupportFlow ticket with a valid status. if ($ticket->post_type != SupportFlow()->post_type || !array_key_exists($ticket->post_status, SupportFlow()->post_statuses)) { $ticket_id = false; } } // Back-compat with old-style secrets. if (!$ticket_id && preg_match('#\\[([a-zA-Z0-9]{8})\\]$#', $subject, $matches)) { $ticket_id = SupportFlow()->get_ticket_from_secret($matches[1]); } // Add anyone else that was in the 'to' or 'cc' fields as customers $customers = array(); $fields = array('to', 'cc'); foreach ($fields as $field) { if (!empty($email->headers->{$field})) { foreach ($email->headers->{$field} as $recipient) { $email_address = $recipient->mailbox . '@' . $recipient->host; if (is_email($email_address) && $email_address != SupportFlow()->extend->emails->from_address && strcasecmp($email_address, $to) != 0) { $customers[] = $email_address; } } } } $customers[] = $reply_author_email; $customers = apply_filters('supportflow_new_email_customers', $customers, $email, $ticket_id, $email_account_id); $message = SupportFlow()->sanitize_ticket_reply($message); if ($ticket_id) { $reply_args = array('reply_author' => $reply_author, 'reply_author_email' => $reply_author_email); SupportFlow()->update_ticket_customers($ticket_id, $customers, true); SupportFlow()->add_ticket_reply($ticket_id, $message, $reply_args); } else { // If this wasn't in reply to an existing message, create a new ticket $new_ticket_args = array('subject' => $subject, 'reply_author' => $reply_author, 'reply_author_email' => $reply_author_email, 'message' => $message, 'customer_email' => $customers, 'email_account' => $email_account_id); $ticket_id = SupportFlow()->create_ticket($new_ticket_args); } $all_replies = SupportFlow()->get_ticket_replies($ticket_id); $new_reply = $all_replies[count($all_replies) - 1]; foreach ($new_attachment_ids as $new_attachment_id) { // Save the attachment ID as post meta of reply add_post_meta($new_reply->ID, 'sf_attachments', $new_attachment_id); SupportFlow()->extend->attachments->insert_attachment_secret_key($new_attachment_id); // It doesn't do anything special other than making sure file is not shown as unattached in media page wp_update_post(array('ID' => $new_attachment_id, 'post_parent' => $ticket_id)); } // Store the original email ID so we don't accidentally dupe it $email_id = trim($email->headers->message_id, '<>'); if (is_object($new_reply)) { update_post_meta($new_reply->ID, self::email_id_key, $email_id); } SupportFlow()->extend->logger->log('email_retrieve', __METHOD__, sprintf(__('Successfully imported e-mail from %s.', 'supportflow'), $reply_author_email)); return true; }
/** * Get user id of all the users that will receive e-mail notifications for a ticket reply * * @param type $ticket_id * * @return type array */ public function get_notified_user($ticket_id) { $tags = wp_get_post_terms($ticket_id, SupportFlow()->tags_tax, array('fields' => 'slugs')); $email_account = get_post_meta($ticket_id, 'email_account', true); $email_notifications_override = get_post_meta($ticket_id, 'email_notifications_override', true); if (!is_array($email_notifications_override)) { $email_notifications_override = array(); } $notifications_settings = $this->get_notifications_settings(null, true); $allowed_users = array(); foreach ($notifications_settings as $notifications_setting) { if (in_array($notifications_setting['user_id'], $allowed_users)) { continue; } if ('tags' == $notifications_setting['privilege_type']) { $user_notified = in_array($notifications_setting['privilege_id'], $tags); } elseif ('email_accounts' == $notifications_setting['privilege_type']) { $user_notified = $email_account == $notifications_setting['privilege_id']; } if ($user_notified) { $allowed_users[] = $notifications_setting['user_id']; } } foreach ($email_notifications_override as $user_id => $status) { if ('disable' == $status && in_array($user_id, $allowed_users)) { unset($allowed_users[array_search($user_id, $allowed_users)]); } if ('enable' == $status && !in_array($user_id, $allowed_users)) { $allowed_users[] = $user_id; } } return $allowed_users; }
/** * Add a new E-Mail account to database */ function add_email_account($imap_host, $imap_port, $imap_ssl, $smtp_host, $smtp_port, $smtp_ssl, $username, $password, $test_login = true) { global $phpmailer; $email_accounts =& $this->email_accounts; $imap_host = sanitize_text_field($imap_host); $imap_port = intval($imap_port); $imap_ssl = (bool) $imap_ssl; $smtp_host = sanitize_text_field($smtp_host); $smtp_port = intval($smtp_port); $smtp_ssl = (bool) $smtp_ssl; $username = sanitize_text_field($username); $password = sanitize_text_field($password); if ($this->email_account_exists($imap_host, $smtp_host, $username)) { SupportFlow()->extend->logger->log('email_accounts', __METHOD__, __('Account already exists.', 'supportflow'), compact('imap_host', 'imap_port', 'imap_ssl', 'smtp_host', 'smtp_port', 'smtp_ssl', 'username')); return self::ACCOUNT_EXISTS; } if ($test_login) { imap_timeout(IMAP_OPENTIMEOUT, apply_filters('supportflow_imap_open_timeout', 5)); $ssl = $imap_ssl ? '/ssl' : ''; $ssl = apply_filters('supportflow_imap_ssl', $ssl, $imap_host); $mailbox = '{' . $imap_host . ':' . $imap_port . $ssl . '}'; if ($imap_stream = imap_open($mailbox, $username, $password, 0, 0)) { SupportFlow()->extend->logger->log('email_accounts', __METHOD__, __('Successfully opened IMAP connection.', 'supportflow'), compact('imap_host', 'imap_port', 'imap_ssl', 'smtp_host', 'smtp_port', 'smtp_ssl', 'username', 'mailbox')); imap_close($imap_stream); } else { $imap_errors = imap_errors(); $error = $imap_errors[0]; SupportFlow()->extend->logger->log('email_accounts', __METHOD__, __('Failed to open IMAP connection.', 'supportflow'), compact('imap_host', 'imap_port', 'imap_ssl', 'smtp_host', 'smtp_port', 'smtp_ssl', 'username', 'mailbox', 'imap_errors')); if ((string) strpos($error, 'Host not found') != '') { return self::IMAP_HOST_NOT_FOUND; } elseif ((string) strpos($error, 'Timed out') != '') { return self::IMAP_TIME_OUT; } elseif ((string) strpos($error, 'Invalid credentials') != '') { return self::IMAP_INVALID_CREDENTIALS; } else { return self::IMAP_CONNECTION_FAILED; } } // Initialize PHPMailer wp_mail('', '', ''); // Set PHPMailer SMTP settings $phpmailer->IsSMTP(); $phpmailer->Host = $smtp_host; $phpmailer->Port = $smtp_port; $phpmailer->SMTPSecure = $smtp_ssl ? 'ssl' : ''; $phpmailer->SMTPAutoTLS = $smtp_ssl; $phpmailer->Username = $username; $phpmailer->Password = $password; $phpmailer->SMTPAuth = true; // $phpmail raise fatal error on SMTP connect failure try { $smtp_authentication = $phpmailer->smtpConnect(); } catch (Exception $e) { $smtp_authentication = false; SupportFlow()->extend->logger->log('email_accounts', __METHOD__, sprintf(__('PHPMailer exception: %s.', 'supportflow'), $e->getMessage()), compact('smtp_host', 'smtp_port', 'smtp_ssl', 'username')); } SupportFlow()->extend->logger->log('email_accounts', __METHOD__, $smtp_authentication ? __('Successfully authenticated with SMTP server.', 'supportflow') : __('Failed to authenticate with SMTP server.', 'supportflow'), compact('imap_host', 'imap_port', 'imap_ssl', 'smtp_host', 'smtp_port', 'smtp_ssl', 'username', 'mailbox')); if (!$smtp_authentication) { return self::SMTP_AUTHENTICATION_FAILED; } } $email_accounts[] = array('imap_host' => $imap_host, 'imap_port' => $imap_port, 'imap_ssl' => $imap_ssl, 'smtp_host' => $smtp_host, 'smtp_port' => $smtp_port, 'smtp_ssl' => $smtp_ssl, 'username' => $username, 'password' => $password); update_option('sf_email_accounts', $email_accounts); return self::SUCCESS; }
/** * When a ticket is saved or updated, make sure we save the customer * and new reply data */ public function action_save_post($ticket_id) { $email_account_id = get_post_meta($ticket_id, 'email_account', true); $email_account = SupportFlow()->extend->email_accounts->get_email_account($email_account_id); $ticket_lock = null == $email_account && '' != $email_account; if (SupportFlow()->post_type != get_post_type($ticket_id)) { return; } if (isset($_POST['customers'])) { $customers = array_map('sanitize_email', explode(',', $_POST['customers'])); SupportFlow()->update_ticket_customers($ticket_id, $customers); } if (isset($_POST['post_email_account']) && is_numeric($_POST['post_email_account']) && '' == $email_account_id) { $email_account = (int) $_POST['post_email_account']; update_post_meta($ticket_id, 'email_account', $email_account); } if (isset($_POST['post_email_notifications_override']) && in_array($_POST['post_email_notifications_override'], array('default', 'enable', 'disable'))) { $email_notifications_override = get_post_meta($ticket_id, 'email_notifications_override', true); $email_notifications_override[get_current_user_id()] = $_POST['post_email_notifications_override']; update_post_meta($ticket_id, 'email_notifications_override', $email_notifications_override); } if (isset($_POST['reply']) && !empty($_POST['reply']) && !$ticket_lock) { $reply = $_POST['reply']; if (isset($_POST['insert-signature']) && 'on' == $_POST['insert-signature']) { $agent_signature = get_user_meta(get_current_user_id(), 'sf_user_signature', true); if (!empty($agent_signature)) { $reply .= "\n\n-----\n{$agent_signature}"; } } $reply = SupportFlow()->sanitize_ticket_reply($reply); $visibility = !empty($_POST['mark-private']) ? 'private' : 'public'; if (!empty($_POST['reply-attachments'])) { $attachements = explode(',', trim($_POST['reply-attachments'], ',')); // Remove same attachment added more than once $attachements = array_unique($attachements); // Remove non-int attachment ID's from array $attachements = array_filter($attachements, function ($val) { return (string) (int) $val === (string) $val; }); $attachment_ids = array_map('intval', $attachements); } else { $attachment_ids = ''; } $cc = !empty($_POST['cc']) ? SupportFlow()->extract_email_ids($_POST['cc']) : ''; $bcc = !empty($_POST['bcc']) ? SupportFlow()->extract_email_ids($_POST['bcc']) : ''; $reply_args = array('post_status' => $visibility, 'attachment_ids' => $attachment_ids, 'cc' => $cc, 'bcc' => $bcc); SupportFlow()->add_ticket_reply($ticket_id, $reply, $reply_args); } }
/** * Generate a link that shows matching tickets in all ticket page * * @param string $link_tag Slug of tag * @param string $post_status Post statuses that should be shown in all tickets page * @param string $link_value Value of hyperlink that should be shown to user * * @return string A hyperlink */ function get_post_link_by_tag($link_tag = null, $post_status = null, $link_value = null) { $link = '<a href="edit.php?%s%s%s">%s</a>'; $post_type = 'post_type=' . SupportFlow()->post_type; $post_status = is_null($post_status) ? '' : "&post_status={$post_status}"; $date = is_null($link_tag) ? '' : '&' . SupportFlow()->tags_tax . "={$link_tag}"; $value = is_null($link_value) ? '' : "{$link_value}"; return sprintf($link, $post_type, $post_status, $date, $value); }