/**
  * Save the core fields.
  *
  * Core fields are processed differently and won't use the same
  * saving function as the standard custom fields of the same type.
  *
  * @since 3.2.0
  *
  * @param int   $post_id ID of the post being saved
  * @param array $field   Field array
  * @param mixed $value   Field new value
  *
  * @return void
  */
 public function save_core_field($post_id, $field, $value)
 {
     switch ($field['name']) {
         case 'assignee':
             if ($value !== get_post_meta($post_id, '_wpas_assignee', true)) {
                 wpas_assign_ticket($post_id, $value, $field['args']['log']);
             }
             break;
     }
 }
/**
 * Insert a new ticket in the database
 *
 * This function is a wrapper function for wp_insert_post
 * with additional checks specific to the ticketing system
 *
 * @param array    $data     Ticket (post) data
 * @param bool|int $post_id  Post ID for an update
 * @param bool|int $agent_id ID of the agent to assign ticket to
 *
 * @return bool|int|WP_Error
 */
function wpas_insert_ticket($data = array(), $post_id = false, $agent_id = false)
{
    // First of all we want to set the ticket author so that we can check if (s)he is allowed to open a ticket or not.
    if (empty($data['post_author'])) {
        global $current_user;
        $data['post_author'] = $current_user->ID;
    }
    if (!user_can($data['post_author'], 'create_ticket')) {
        return false;
    }
    $update = false;
    /* If a post ID is passed we make sure the post actually exists before trying to update it. */
    if (false !== $post_id) {
        $post = get_post(intval($post_id));
        if (is_null($post)) {
            return false;
        }
        $update = true;
    }
    $defaults = array('post_content' => '', 'post_name' => '', 'post_title' => '', 'post_status' => 'queued', 'post_type' => 'ticket', 'post_author' => '', 'ping_status' => 'closed', 'comment_status' => 'closed');
    /* Add the post ID if this is an update. */
    if ($update) {
        $defaults['ID'] = $post_id;
    }
    /* Parse the input data. */
    $data = wp_parse_args($data, $defaults);
    /* Sanitize the data */
    if (isset($data['post_title']) && !empty($data['post_title'])) {
        $data['post_title'] = wp_strip_all_tags($data['post_title']);
    }
    if (!empty($data['post_content'])) {
        $data['post_content'] = strip_shortcodes($data['post_content']);
    }
    /**
     * Filter the data right before inserting it in the post.
     * 
     * @var array
     */
    $data = apply_filters('wpas_open_ticket_data', $data);
    if (isset($data['post_name']) && !empty($data['post_name'])) {
        $data['post_name'] = sanitize_text_field($data['post_name']);
    }
    /**
     * Fire wpas_before_open_ticket just before the post is actually
     * inserted in the database.
     */
    do_action('wpas_open_ticket_before', $data, $post_id);
    /**
     * Insert the post in database using the regular WordPress wp_insert_post
     * function with default values corresponding to our post type structure.
     * 
     * @var boolean
     */
    $ticket_id = wp_insert_post($data, false);
    if (false === $ticket_id) {
        /**
         * Fire wpas_open_ticket_failed if the ticket couldn't be inserted.
         */
        do_action('wpas_open_ticket_failed', $data, $post_id);
        return false;
    }
    /* Set the ticket as open. */
    add_post_meta($ticket_id, '_wpas_status', 'open', true);
    if (false === $agent_id) {
        $agent_id = wpas_find_agent($ticket_id);
    }
    /**
     * Fire wpas_open_ticket_before_assigned after the post is successfully submitted but before it has been assigned to an agent.
     *
     * @since 3.2.6
     */
    do_action('wpas_open_ticket_before_assigned', $ticket_id, $data);
    /* Assign an agent to the ticket */
    wpas_assign_ticket($ticket_id, apply_filters('wpas_new_ticket_agent_id', $agent_id, $ticket_id, $agent_id), false);
    /**
     * Fire wpas_after_open_ticket just after the post is successfully submitted and assigned.
     */
    do_action('wpas_open_ticket_after', $ticket_id, $data);
    return $ticket_id;
}
 /**
  * Save the custom fields.
  *
  * The following method will get all options,
  * check if they have  a submissed value, prefix and save it to the DB.
  * 
  * @param  (integer) $post_id Post ID
  * @since 3.0.0
  */
 public function save($post_id = '')
 {
     /* Need the parent object */
     global $wpas_cf;
     /**
      * Clear! We can go ahead now...
      */
     $options = $wpas_cf->get_custom_fields();
     /**
      * Save the possible messages in this array
      */
     $messages = array();
     /**
      * Save all notifications to send in this array for a later expedition
      */
     $notify = array();
     /**
      * If some of the fields are to be logged in the ticket history, we save it here
      */
     $log = array();
     /* Go through all our options */
     foreach ($options as $option) {
         $option_name = 'wpas_' . sanitize_text_field($option['name']);
         $option_args = $option['args'];
         /* Prepare current value */
         if (isset($_POST[$option_name])) {
             $value = function_exists($option_args['sanitize']) ? $option_args['sanitize']($_POST[$option_name]) : sanitize_text_field($_POST[$option_name]);
         }
         /* Use a custom saving function if the save_callback is defined */
         if (false !== $option_args['save_callback']) {
             if (is_null($option_args['save_callback'])) {
                 continue;
             }
             if (function_exists($option_args['save_callback'])) {
                 call_user_func($option_args['save_callback'], $value, $post_id);
                 continue;
             }
         }
         /* Process the agent (re)attribution differently */
         if ('assignee' === $option['name']) {
             /* Don't od anything if the agent didn't change */
             if ($_POST[$option_name] == get_post_meta($post_id, '_wpas_assignee', true)) {
                 continue;
             }
             wpas_assign_ticket($post_id, $_POST[$option_name], $option_args['log']);
             continue;
         }
         /* We handle different option types differently */
         if ('taxonomy' != $option_args['callback']) {
             /* Form the meta key */
             $key = "_{$option_name}";
             /* Get current option */
             $current = get_post_meta($post_id, $key, true);
             /**
              * First case scenario
              *
              * The option exists in DB but there is no value
              * for it in the POST. This is often the case
              * for checkboxes.
              *
              * Action: Delete option
              */
             if ('' != $current && !isset($_POST[$option_name])) {
                 /* Delete the post meta */
                 delete_post_meta($post_id, $key, $current);
                 /* Log the action */
                 if (true === $option_args['log']) {
                     $log[] = array('action' => 'deleted', 'label' => wpas_get_field_title($option), 'value' => $current, 'field_id' => $option['name']);
                 }
             } elseif ('' != $current && isset($_POST[$option_name])) {
                 /* If an actual value is set, we udpate the post meta */
                 if ('' != $value && $current != $value) {
                     update_post_meta($post_id, $key, $value, $current);
                     /* Log the action */
                     if (true === $option_args['log']) {
                         $log[] = array('action' => 'updated', 'label' => wpas_get_field_title($option), 'value' => $value, 'field_id' => $option['name']);
                     }
                 } elseif ('' == $value) {
                     delete_post_meta($post_id, $key, $current);
                     /* Log the action */
                     if (true === $option_args['log']) {
                         $log[] = array('action' => 'deleted', 'label' => wpas_get_field_title($option), 'value' => $current, 'field_id' => $option['name']);
                     }
                 }
             } elseif ('' == $current && isset($_POST[$option_name])) {
                 /* Let's not add an empty value */
                 if ('' != $value) {
                     add_post_meta($post_id, $key, $value, true);
                     /* Log the action */
                     if (true === $option_args['log']) {
                         $log[] = array('action' => 'added', 'label' => wpas_get_field_title($option), 'value' => $value, 'field_id' => $option['name']);
                     }
                 }
             } else {
                 // Do nothing
             }
         } elseif ('taxonomy' == $option_args['callback']) {
             /* Check if this taxonomy has to be handled as a select */
             if (true === $option_args['taxo_std']) {
                 continue;
             }
             /* Clean the taxonomy name */
             $taxonomy = substr($option_name, 5);
             /* If no value is submitted we delete the term relationship */
             if (!isset($_POST[$option_name]) || empty($_POST[$option_name])) {
                 $terms = wp_get_post_terms($post_id, $taxonomy);
                 if (!empty($terms)) {
                     wp_delete_object_term_relationships($post_id, $option_name);
                     /* Log the action */
                     if (true === $option_args['log']) {
                         $log[] = array('action' => 'deleted', 'label' => wpas_get_field_title($option), 'value' => $current, 'field_id' => $option['name']);
                     }
                 }
                 continue;
             }
             /* Get all the terms for this ticket / taxo (we should have only one term) */
             $terms = get_the_terms($post_id, $taxonomy);
             /**
              * As the taxonomy is handled like a select, we should have only one value. At least
              * that's what we want. Hence, we loop through the possible multiple terms (which
              * shouldn't happen) and only keep the last one.
              */
             if (is_array($terms)) {
                 foreach ($terms as $term) {
                     $the_term = $term->term_id;
                 }
             } else {
                 $the_term = '';
             }
             /* Finally we save the new terms if changed */
             if ($the_term !== (int) $value) {
                 $term = get_term_by('id', (int) $value, $taxonomy);
                 if (false === $term) {
                     continue;
                 }
                 /**
                  * Apply the get_term filters.
                  * 
                  * @var object
                  */
                 $term = get_term($term, $taxonomy);
                 wp_set_object_terms($post_id, (int) $value, $taxonomy, false);
                 /* Log the action */
                 if (true === $option_args['log']) {
                     $log[] = array('action' => 'updated', 'label' => wpas_get_field_title($option), 'value' => $term->name, 'field_id' => $option['name']);
                 }
             }
         }
         /**
          * Fired right after the option is updated
          */
         do_action("wpas_cf_updated_{$option_name}");
         /**
          * If a message is associated to this option, we add it now
          */
         if (isset($option_args['message'])) {
             $messages[] = $option_args['message'];
         }
         /**
          * If an e-mail notification has to be sent we store it temporarily
          */
         if (isset($option_args['notification'])) {
             $notify[] = $option_args['notification'];
         }
     }
     /**
      * Log the changes
      */
     if (!empty($log)) {
         wpas_log($post_id, $log);
     }
 }