Want more features on Pastebin? Sign Up, it's FREE!
Guest

EM Recurring Tickets: classes/em-event.php

By: a guest on May 9th, 2013  |  syntax: PHP  |  size: 98.05 KB  |  views: 90  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. <?php
  2. /**
  3.  * Get an event in a db friendly way, by checking globals and passed variables to avoid extra class instantiations
  4.  * @param mixed $id
  5.  * @param mixed $search_by
  6.  * @return EM_Event
  7.  */
  8. function em_get_event($id = false, $search_by = 'event_id') {
  9.         global $EM_Event;
  10.         //check if it's not already global so we don't instantiate again
  11.         if( is_object($EM_Event) && get_class($EM_Event) == 'EM_Event' ){
  12.                 if( is_object($id) && $EM_Event->post_id == $id->ID ){
  13.                         return apply_filters('em_get_event', $EM_Event);
  14.                 }elseif( !is_object($id) ){
  15.                         if( $search_by == 'event_id' && $EM_Event->event_id == $id ){
  16.                                 return apply_filters('em_get_event', $EM_Event);
  17.                         }elseif( $search_by == 'post_id' && $EM_Event->post_id == $id ){
  18.                                 return apply_filters('em_get_event', $EM_Event);
  19.                         }
  20.                 }
  21.         }
  22.         if( is_object($id) && get_class($id) == 'EM_Event' ){
  23.                 return apply_filters('em_get_event', $id);
  24.         }else{
  25.                 return apply_filters('em_get_event', new EM_Event($id,$search_by));
  26.         }
  27. }
  28. /**
  29.  * Event Object. This holds all the info pertaining to an event, including location and recurrence info.
  30.  * An event object can be one of three "types" a recurring event, recurrence of a recurring event, or a single event.
  31.  * The single event might be part of a set of recurring events, but if loaded by specific event id then any operations and saves are
  32.  * specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
  33.  *
  34.  * @author marcus
  35.  */
  36. //TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
  37. //TODO Integrate recurrences into events table
  38. //FIXME If you create a super long recurrence timespan, there could be thousands of events... need an upper limit here.
  39. class EM_Event extends EM_Object{
  40.         /* Field Names */
  41.         var $event_id;
  42.         var $post_id;
  43.         var $event_slug;
  44.         var $event_owner;
  45.         var $event_name;
  46.         var $event_start_time;
  47.         var $event_end_time;
  48.         var $event_all_day;
  49.         var $event_start_date;
  50.         var $event_end_date;
  51.         var $post_content;
  52.         var $event_rsvp;
  53.         var $event_rsvp_date;
  54.         var $event_rsvp_time = "00:00:00";
  55.         var $event_spaces;
  56.         var $location_id;
  57.         var $recurrence_id;
  58.         var $event_status;
  59.         var $event_date_created;
  60.         var $event_date_modified;
  61.         var $blog_id;
  62.         var $group_id; 
  63.         /**
  64.          * Populated with the non-hidden event post custom fields (i.e. not starting with _)
  65.          * @var array
  66.          */
  67.         var $event_attributes = array();
  68.         /* Recurring Specific Values */
  69.         var $recurrence;
  70.         var $recurrence_interval;
  71.         var $recurrence_freq;
  72.         var $recurrence_byday;
  73.         var $recurrence_days = 0;
  74.         var $recurrence_byweekno;
  75.         /* anonymous submission information */
  76.         var $event_owner_anonymous;
  77.         var $event_owner_name;
  78.         var $event_owner_email;
  79.         /**
  80.          * Previously used to give this object shorter property names for db values (each key has a name) but this is now depreciated, use the db field names as properties. This propertey provides extra info about the db fields.
  81.          * @var array
  82.          */
  83.         var $fields = array(
  84.                 'event_id' => array( 'name'=>'id', 'type'=>'%d' ),
  85.                 'post_id' => array( 'name'=>'post_id', 'type'=>'%d' ),
  86.                 'event_slug' => array( 'name'=>'slug', 'type'=>'%s', 'null'=>true ),
  87.                 'event_owner' => array( 'name'=>'owner', 'type'=>'%d', 'null'=>true ),
  88.                 'event_name' => array( 'name'=>'name', 'type'=>'%s', 'null'=>true ),
  89.                 'event_start_time' => array( 'name'=>'start_time', 'type'=>'%s', 'null'=>true ),
  90.                 'event_end_time' => array( 'name'=>'end_time', 'type'=>'%s', 'null'=>true ),
  91.                 'event_all_day' => array( 'name'=>'all_day', 'type'=>'%d', 'null'=>true ),
  92.                 'event_start_date' => array( 'name'=>'start_date', 'type'=>'%s', 'null'=>true ),
  93.                 'event_end_date' => array( 'name'=>'end_date', 'type'=>'%s', 'null'=>true ),
  94.                 'post_content' => array( 'name'=>'notes', 'type'=>'%s', 'null'=>true ),
  95.                 'event_rsvp' => array( 'name'=>'rsvp', 'type'=>'%d', 'null'=>true ), //has a default, so can be null/excluded
  96.                 'event_rsvp_date' => array( 'name'=>'rsvp_date', 'type'=>'%s', 'null'=>true ),
  97.                 'event_rsvp_time' => array( 'name'=>'rsvp_time', 'type'=>'%s', 'null'=>true ),
  98.                 'event_spaces' => array( 'name'=>'spaces', 'type'=>'%d', 'null'=>true),
  99.                 'location_id' => array( 'name'=>'location_id', 'type'=>'%d', 'null'=>true ),
  100.                 'recurrence_id' => array( 'name'=>'recurrence_id', 'type'=>'%d', 'null'=>true ),
  101.                 'event_status' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
  102.                 'event_private' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
  103.                 'event_date_created' => array( 'name'=>'date_created', 'type'=>'%s', 'null'=>true ),
  104.                 'event_date_modified' => array( 'name'=>'date_modified', 'type'=>'%s', 'null'=>true ),
  105.                 'event_attributes' => array( 'name'=>'attributes', 'type'=>'%s', 'null'=>true ),
  106.                 'blog_id' => array( 'name'=>'blog_id', 'type'=>'%d', 'null'=>true ),
  107.                 'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
  108.                 'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
  109.                 'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
  110.                 'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
  111.                 'recurrence_days' => array( 'name'=>'days', 'type'=>'%d', 'null'=>true ), //daily,weekly,monthly?
  112.                 'recurrence_byday' => array( 'name'=>'byday', 'type'=>'%s', 'null'=>true ), //if weekly or monthly, what days of the week?
  113.                 'recurrence_byweekno' => array( 'name'=>'byweekno', 'type'=>'%d', 'null'=>true ), //if monthly which week (-1 is last)
  114.         );
  115.         var $post_fields = array('event_slug','event_owner','event_name','event_attributes','post_id','post_content'); //fields that won't be taken from the em_events table anymore
  116.         var $recurrence_fields = array('recurrence_interval', 'recurrence_freq', 'recurrence_days', 'recurrence_byday', 'recurrence_byweekno');
  117.        
  118.         var $image_url = '';
  119.         /**
  120.          * Timestamp of start date/time
  121.          * @var int
  122.          */
  123.         var $start;
  124.         /**
  125.          * Timestamp of end date/time
  126.          * @var int
  127.          */
  128.         var $end;
  129.         /**
  130.          * Timestamp for booking cut-off date/time
  131.          * @var int
  132.          */
  133.         var $rsvp_end;
  134.         /**
  135.          * Created on timestamp, taken from DB, converted to TS
  136.          * @var int
  137.          */
  138.         var $created;
  139.         /**
  140.          * Created on timestamp, taken from DB, converted to TS
  141.          * @var int
  142.          */
  143.         var $modified;
  144.        
  145.         /**
  146.          * @var EM_Location
  147.          */
  148.         var $location;
  149.         /**
  150.          * @var EM_Bookings
  151.          */
  152.         var $bookings;
  153.         /**
  154.          * The contact person for this event
  155.          * @var WP_User
  156.          */
  157.         var $contact;
  158.         /**
  159.          * The category object
  160.          * @var EM_Category
  161.          */
  162.         var $category;
  163.         /**
  164.          * If there are any errors, they will be added here.
  165.          * @var array
  166.          */
  167.         var $errors = array(); 
  168.         /**
  169.          * If something was successful, a feedback message might be supplied here.
  170.          * @var string
  171.          */
  172.         var $feedback_message;
  173.         /**
  174.          * Any warnings about an event (e.g. bad data, recurrence, etc.)
  175.          * @var string
  176.          */
  177.         var $warnings;
  178.         /**
  179.          * Array of dbem_event field names required to create an event
  180.          * @var array
  181.          */
  182.         var $required_fields = array('event_name', 'event_start_date');
  183.         var $mime_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
  184.         /**
  185.          * previous status of event when instantiated
  186.          * @access protected
  187.          * @var mixed
  188.          */
  189.         var $previous_status = 0;
  190.        
  191.         /* Post Variables - copied out of post object for easy IDE reference */
  192.         var $ID;
  193.         var $post_author;
  194.         var $post_date;
  195.         var $post_date_gmt;
  196.         var $post_title;
  197.         var $post_excerpt;
  198.         var $post_status;
  199.         var $comment_status;
  200.         var $ping_status;
  201.         var $post_password;
  202.         var $post_name;
  203.         var $to_ping;
  204.         var $pinged;
  205.         var $post_modified;
  206.         var $post_modified_gmt;
  207.         var $post_content_filtered;
  208.         var $post_parent;
  209.         var $guid;
  210.         var $menu_order;
  211.         var $post_type;
  212.         var $post_mime_type;
  213.         var $comment_count;
  214.         var $ancestors;
  215.         var $filter;
  216.        
  217.         /**
  218.          * Initialize an event. You can provide event data in an associative array (using database table field names), an id number, or false (default) to create empty event.
  219.          * @param mixed $event_data
  220.          * @param mixed $search_by default is post_id, otherwise it can be by event_id as well.
  221.          * @return null
  222.          */
  223.         function __construct($id = false, $search_by = 'event_id') {
  224.                 global $wpdb;
  225.                 if( is_array($id) ){
  226.                         //deal with the old array style, but we can't supply arrays anymore
  227.                         $id = (!empty($id['event_id'])) ? $id['event_id'] : $id['post_id'];
  228.                         $search_by = (!empty($id['event_id'])) ? 'event_id':'post_id';
  229.                 }
  230.                 $is_post = !empty($id->ID) && ($id->post_type == EM_POST_TYPE_EVENT || $id->post_type == 'event-recurring');
  231.                 if( is_numeric($id) || $is_post ){ //only load info if $id is a number
  232.                         if($search_by == 'event_id' && !$is_post ){
  233.                                 //search by event_id, get post_id and blog_id (if in ms mode) and load the post
  234.                                 $results = $wpdb->get_row($wpdb->prepare("SELECT post_id, blog_id FROM ".EM_EVENTS_TABLE." WHERE event_id=%d",$id), ARRAY_A);
  235.                                 if( is_multisite() && (is_numeric($results['blog_id']) || $results['blog_id']=='' ) ){
  236.                                     if( $results['blog_id']=='' )  $results['blog_id'] = get_current_site()->blog_id;
  237.                                         $event_post = get_blog_post($results['blog_id'], $results['post_id']);
  238.                                         $search_by = $results['blog_id'];
  239.                                 }else{
  240.                                         $event_post = get_post($results['post_id']);   
  241.                                 }
  242.                         }else{
  243.                                 if(!$is_post){
  244.                                         if( is_multisite() && (is_numeric($search_by) || $search_by == '') ){
  245.                                             if( $search_by == '' ) $search_by = get_current_site()->blog_id;
  246.                                                 //we've been given a blog_id, so we're searching for a post id
  247.                                                 $event_post = get_blog_post($search_by, $id);
  248.                                         }else{
  249.                                                 //search for the post id only
  250.                                                 $event_post = get_post($id);
  251.                                         }
  252.                                 }else{
  253.                                         $event_post = $id;
  254.                                 }
  255.                         }
  256.                         $this->load_postdata($event_post, $search_by);
  257.                 }
  258.                 $this->recurrence = $this->is_recurring() ? 1:0;
  259.                 //if(defined('trashtest')){ print_r($this); die("got here");}
  260.                 //Do it here so things appear in the po file.
  261.                 $this->status_array = array(
  262.                         0 => __('Pending','dbem'),
  263.                         1 => __('Approved','dbem')
  264.                 );
  265.                 do_action('em_event', $this, $id, $search_by);
  266.         }
  267.        
  268.         function load_postdata($event_post, $search_by = false){
  269.                 if( is_object($event_post) ){
  270.                         //load post data - regardless
  271.                         $this->post_id = $event_post->ID;
  272.                         $this->event_name = $event_post->post_title;
  273.                         $this->event_owner = $event_post->post_author;
  274.                         $this->post_content = $event_post->post_content;
  275.                         $this->event_slug = $event_post->post_name;
  276.                         $this->event_modified = $event_post->post_modified;
  277.                         foreach( $event_post as $key => $value ){ //merge post object into this object
  278.                                 $this->$key = $value;
  279.                         }
  280.                         $this->previous_status = $this->event_status; //so we know about updates
  281.                         $this->recurrence = $this->is_recurring() ? 1:0;
  282.                         //load meta data and other related information
  283.                         if( $event_post->post_status != 'auto-draft' ){
  284.                             $event_meta = $this->get_event_meta($search_by);
  285.                                 //Get custom fields and post meta
  286.                                 foreach($event_meta as $event_meta_key => $event_meta_val){
  287.                                         $field_name = substr($event_meta_key, 1);
  288.                                         if($event_meta_key[0] != '_'){
  289.                                                 $this->event_attributes[$event_meta_key] = ( count($event_meta_val) > 1 ) ? $event_meta_val:$event_meta_val[0];                                
  290.                                         }elseif( is_string($field_name) && !in_array($field_name, $this->post_fields) ){
  291.                                                 if( array_key_exists($field_name, $this->fields) ){
  292.                                                         $this->$field_name = $event_meta_val[0];
  293.                                                 }elseif( in_array($field_name, array('event_owner_name','event_owner_anonymous','event_owner_email')) ){
  294.                                                         $this->$field_name = $event_meta_val[0];
  295.                                                 }
  296.                                         }
  297.                                 }
  298.                                 //Start/End times should be available as timestamp
  299.                                 $this->start = strtotime($this->event_start_date." ".$this->event_start_time);
  300.                                 $this->end = strtotime($this->event_end_date." ".$this->event_end_time);
  301.                                 if( !empty($this->event_rsvp_date ) ){
  302.                                     $this->rsvp_end = strtotime($this->event_rsvp_date." ".$this->event_rsvp_time);
  303.                                 }
  304.                                 //quick compatability fix in case _event_id isn't loaded or somehow got erased in post meta
  305.                                 if( empty($this->event_id) && !$this->is_recurring() ){
  306.                                         global $wpdb;
  307.                                         $event_array = $wpdb->get_row('SELECT * FROM '.EM_EVENTS_TABLE. ' WHERE post_id='.$event_post->ID, ARRAY_A);
  308.                                         if( !empty($event_array['event_id']) ){
  309.                                                 foreach($event_array as $key => $value){
  310.                                                         if( !empty($value) && empty($this->$key) ){
  311.                                                                 update_post_meta($event_post->ID, '_'.$key, $value);
  312.                                                                 $this->$key = $value;
  313.                                                         }
  314.                                                 }
  315.                                         }
  316.                                 }
  317.                         }
  318.                         $this->get_status();
  319.                         $this->compat_keys();
  320.                 }
  321.         }
  322.        
  323.         function get_event_meta($blog_id = false){
  324.                 if( is_numeric($blog_id) && $blog_id > 0 && is_multisite() ){
  325.                         // if in multisite mode, switch blogs quickly to get the right post meta.
  326.                         switch_to_blog($blog_id);
  327.                         $event_meta = get_post_meta($this->post_id);
  328.                         restore_current_blog();
  329.                         $this->blog_id = $blog_id;
  330.                 }else{
  331.                         $event_meta = get_post_meta($this->post_id);
  332.                 }
  333.                 return $event_meta;
  334.         }
  335.        
  336.         /**
  337.          * Retrieve event information via POST (only used in situations where posts aren't submitted via WP)
  338.          * @return boolean
  339.          */
  340.         function get_post($validate = true){   
  341.                 global $allowedposttags;
  342.                 //we need to get the post/event name and content.... that's it.
  343.                 $this->post_content = isset($_POST['content']) ? wp_kses( stripslashes($_POST['content']), $allowedposttags):'';
  344.                 $this->event_name = !empty($_POST['event_name']) ? htmlspecialchars_decode(wp_kses_data(htmlspecialchars_decode(stripslashes($_POST['event_name'])))):'';
  345.                 $this->post_type = ($this->is_recurring() || !empty($_POST['recurring'])) ? 'event-recurring':EM_POST_TYPE_EVENT;
  346.                 //don't forget categories!
  347.                 $this->get_categories()->get_post();
  348.                 //anonymous submissions and guest basic info
  349.                 if( !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') && empty($this->event_id) ){
  350.                         $this->event_owner_anonymous = 1;
  351.                         $this->event_owner_name = !empty($_POST['event_owner_name']) ? wp_kses_data(stripslashes($_POST['event_owner_name'])):'';
  352.                         $this->event_owner_email = !empty($_POST['event_owner_email']) ? wp_kses_data($_POST['event_owner_email']):'';
  353.                 }
  354.                 //get the rest and validate (optional)
  355.                 $this->get_post_meta(false);
  356.                 $result = $validate ? $this->validate():true; //validate both post and meta, otherwise return true
  357.                 return apply_filters('em_event_get_post', $result, $this);             
  358.         }
  359.        
  360.         /**
  361.          * Retrieve event post meta information via POST, which should be always be called when saving the event custom post via WP.
  362.          * @param boolean $validate whether or not to run validation, default is true
  363.          * @return boolean
  364.          */
  365.         function get_post_meta($validate = true){
  366.                 //Grab POST data       
  367.                 $this->event_start_date = ( !empty($_POST['event_start_date']) ) ? wp_kses_data($_POST['event_start_date']) : '';
  368.                 $this->event_end_date = ( !empty($_POST['event_end_date']) ) ? wp_kses_data($_POST['event_end_date']) : $this->event_start_date;
  369.                 //check if this is recurring or not
  370.                 if( !empty($_POST['recurring']) ){
  371.                         $this->recurrence = 1;
  372.                         $this->post_type = 'event-recurring';
  373.                 }
  374.                 //Get Location info
  375.                 if( !get_option('dbem_locations_enabled') || (!empty($_POST['no_location']) && !get_option('dbem_require_location',true)) || (empty($_POST['location_id']) && !get_option('dbem_require_location',true) && get_option('dbem_use_select_for_locations')) ){
  376.                         $this->location_id = 0;
  377.                 }elseif( !empty($_POST['location_id']) && is_numeric($_POST['location_id']) ){
  378.                         $this->location_id = $_POST['location_id'];    
  379.                 }else{
  380.                         //we're adding a new location, so create an empty location and populate
  381.                         $this->location_id = null;
  382.                         $this->get_location()->get_post(false);
  383.                         $this->get_location()->post_content = ''; //reset post content, as it'll grab the event description otherwise
  384.                 }
  385.                 //Sort out time
  386.                 $this->event_all_day = ( !empty($_POST['event_all_day']) ) ? 1 : 0;
  387.                 if( !$this->event_all_day ){
  388.                         $match = array();
  389.                         foreach( array('event_start_time','event_end_time', 'event_rsvp_time') as $timeName ){
  390.                                 if( !empty($_POST[$timeName]) && preg_match ( '/^([01]\d|2[0-3]):([0-5]\d) ?(AM|PM)?$/', $_POST[$timeName], $match ) ){
  391.                                         if( !empty($match[3]) && $match[3] == 'PM' && $match[1] != 12 ){
  392.                                                 $match[1] = 12+$match[1];
  393.                                         }elseif( !empty($match[3]) && $match[3] == 'AM' && $match[1] == 12 ){
  394.                                                 $match[1] = '00';
  395.                                         }
  396.                                         $this->$timeName = $match[1].":".$match[2].":00";
  397.                                 }else{
  398.                                         $this->$timeName = ($timeName == 'event_start_time') ? "00:00:00":$this->event_start_time;
  399.                                 }
  400.                         }
  401.                 }else{
  402.                         $this->event_start_time = $this->event_end_time = '00:00:00';
  403.                 }
  404.                 //Start/End times should be available as timestamp
  405.                 $this->start = strtotime($this->event_start_date." ".$this->event_start_time);
  406.                 $this->end = strtotime($this->event_end_date." ".$this->event_end_time);
  407.                 //Bookings
  408.                 if( !empty($_POST['event_rsvp']) && $_POST['event_rsvp'] ){
  409.                         $this->get_bookings()->get_tickets()->get_post();
  410.                         $this->event_rsvp = 1;
  411.                         //RSVP cuttoff TIME is set up above where start/end times are as well
  412.                         if( !$this->is_recurring() ){
  413.                                 $this->event_rsvp_date = ( isset($_POST['event_rsvp_date']) ) ? wp_kses_data($_POST['event_rsvp_date']) : $this->event_start_date;
  414.                                 if( empty($this->event_rsvp_date) ){ $this->event_rsvp_time = '00:00:00'; }
  415.                         }
  416.                         $this->event_spaces = ( isset($_POST['event_spaces']) ) ? absint($_POST['event_spaces']):0;
  417.                 }else{
  418.                         $this->event_rsvp = 0;
  419.                         $this->event_rsvp_time = '00:00:00';
  420.                 }
  421.                 //Sort out event attributes - note that custom post meta now also gets inserted here automatically (and is overwritten by these attributes)
  422.                 if(get_option('dbem_attributes_enabled')){
  423.                         global $allowedtags;
  424.                         if( !is_array($this->event_attributes) ){ $this->event_attributes = array(); }
  425.                         $event_available_attributes = em_get_attributes();
  426.                         if( !empty($_POST['em_attributes']) && is_array($_POST['em_attributes']) ){
  427.                                 foreach($_POST['em_attributes'] as $att_key => $att_value ){
  428.                                         if( (in_array($att_key, $event_available_attributes['names']) || array_key_exists($att_key, $this->event_attributes) ) ){
  429.                                                 $this->event_attributes[$att_key] = '';
  430.                                                 $att_vals = count($event_available_attributes['values'][$att_key]);
  431.                                                 if( !empty($att_value) ){
  432.                                                         if( $att_vals <= 1 || ($att_vals > 1 && in_array($att_value, $event_available_attributes['values'][$att_key])) ){
  433.                                                                 $this->event_attributes[$att_key] = stripslashes($att_value);
  434.                                                         }
  435.                                                 }
  436.                                                 if( empty($att_value) && $att_vals > 1){
  437.                                                         $this->event_attributes[$att_key] = stripslashes(wp_kses($event_available_attributes['values'][$att_key][0], $allowedtags));
  438.                                                 }
  439.                                         }
  440.                                 }
  441.                         }
  442.                 }
  443.                 //Set Blog ID
  444.                 if( is_multisite() ){
  445.                         $this->blog_id = get_current_blog_id();
  446.                 }
  447.                 //group id
  448.                 $this->group_id = (!empty($_POST['group_id']) && is_numeric($_POST['group_id'])) ? $_POST['group_id']:0;
  449.                 //Recurrence data
  450.                 if( $this->is_recurring() ){
  451.                         $this->recurrence = 1; //just in case
  452.                         $this->recurrence_freq = ( !empty($_POST['recurrence_freq']) && in_array($_POST['recurrence_freq'], array('daily','weekly','monthly','yearly')) ) ? $_POST['recurrence_freq']:'daily';
  453.                         if( !empty($_POST['recurrence_bydays']) && $this->recurrence_freq == 'weekly' && self::array_is_numeric($_POST['recurrence_bydays']) ){
  454.                                 $this->recurrence_byday = implode( ",", $_POST['recurrence_bydays'] );
  455.                         }elseif( !empty($_POST['recurrence_byday']) && $this->recurrence_freq == 'monthly' ){
  456.                                 $this->recurrence_byday = wp_kses_data($_POST['recurrence_byday']);
  457.                         }
  458.                         $this->recurrence_interval = ( !empty($_POST['recurrence_interval']) && is_numeric($_POST['recurrence_interval']) ) ? $_POST['recurrence_interval']:1;
  459.                         $this->recurrence_byweekno = ( !empty($_POST['recurrence_byweekno']) ) ? wp_kses_data($_POST['recurrence_byweekno']):'';
  460.                         $this->recurrence_days = ( !empty($_POST['recurrence_days']) && is_numeric($_POST['recurrence_days']) ) ? (int) $_POST['recurrence_days']:0;
  461.                 }
  462.                 //categories in MS GLobal
  463.                 if(EM_MS_GLOBAL && !is_main_site()){
  464.                         $this->get_categories()->get_post(); //it'll know what to do
  465.                 }
  466.                 //validate (optional) and return result
  467.                 $this->compat_keys(); //compatability
  468.                 return apply_filters('em_event_get_post', count($this->errors) == 0, $this);
  469.         }
  470.        
  471.         function validate(){
  472.                 $validate_post = true;
  473.                 if( empty($this->event_name) ){
  474.                         $validate_post = false;
  475.                         $this->add_error( sprintf(__("%s is required.", "dbem"), __('Event name','dbem')) );
  476.                 }
  477.                 //anonymous submissions and guest basic info
  478.                 if( !empty($this->event_owner_anonymous) ){
  479.                         if( !is_email($this->event_owner_email) ){
  480.                                 $this->add_error( sprintf(__("%s is required.", "dbem"), __('A valid email','dbem')) );
  481.                         }
  482.                         if( empty($this->event_owner_name) ){
  483.                                 $this->add_error( sprintf(__("%s is required.", "dbem"), __('Your name','dbem')) );
  484.                         }
  485.                 }
  486.                 $validate_tickets = $this->get_bookings()->get_tickets()->validate();
  487.                 $validate_image = $this->image_validate();
  488.                 $validate_meta = $this->validate_meta();
  489.                 return apply_filters('em_event_validate', $validate_post && $validate_image && $validate_meta && $validate_tickets, $this );           
  490.         }
  491.         function validate_meta(){
  492.                 $missing_fields = Array ();
  493.                 foreach ( array('event_start_date') as $field ) {
  494.                         if ( $this->$field == "") {
  495.                                 $missing_fields[$field] = $field;
  496.                         }
  497.                 }
  498.                 if( preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_start_date) && preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_end_date) ){
  499.                         if( strtotime($this->event_start_date . $this->event_start_time) > strtotime($this->event_end_date . $this->event_end_time) ){
  500.                                 $this->add_error(__('Events cannot start after they end.','dbem'));
  501.                         }elseif( $this->is_recurring() && $this->recurrence_days == 0 && strtotime($this->event_start_date . $this->event_start_time) > strtotime($this->event_start_date . $this->event_end_time) ){
  502.                                 $this->add_error(__('Events cannot start after they end.','dbem').' '.__('For recurring events that end the following day, ensure you make your event last 1 or more days.'));
  503.                         }
  504.                 }else{
  505.                         if( !empty($missing_fields['event_start_date']) ) { unset($missing_fields['event_start_date']); }
  506.                         if( !empty($missing_fields['event_end_date']) ) { unset($missing_fields['event_end_date']); }
  507.                         $this->add_error(__('Dates must have correct formatting. Please use the date picker provided.','dbem'));
  508.                 }
  509.                 if( $this->event_rsvp ){
  510.                     if( !$this->get_bookings()->get_tickets()->validate() ){
  511.                         $this->add_error($this->get_bookings()->get_tickets()->get_errors());
  512.                     }
  513.                     if( !empty($this->event_rsvp_date) && !preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_rsvp_date) ){
  514.                                 $this->add_error(__('Dates must have correct formatting. Please use the date picker provided.','dbem'));
  515.                     }
  516.                 }
  517.                 if( get_option('dbem_locations_enabled') && empty($this->location_id) ){ //location ids don't need validating as we're not saving a location
  518.                         if( get_option('dbem_require_location',true) || $this->location_id !== 0 ){
  519.                                 if( !$this->get_location()->validate() ){
  520.                                         $this->add_error($this->get_location()->get_errors());
  521.                                 }
  522.                         }
  523.                 }
  524.                 if ( count($missing_fields) > 0){
  525.                         // TODO Create friendly equivelant names for missing fields notice in validation
  526.                         $this->add_error( __( 'Missing fields: ', 'dbem') . implode ( ", ", $missing_fields ) . ". " );
  527.                 }
  528.                 if ( $this->is_recurring() && ($this->event_end_date == "" || $this->event_end_date == $this->event_start_date) ){
  529.                         $this->add_error( __( 'Since the event is repeated, you must specify an event end date greater than the start date.', 'dbem' ));
  530.                 }
  531.                 return apply_filters('em_event_validate_meta', count($this->errors) == 0, $this );
  532.         }
  533.        
  534.         /**
  535.          * Will save the current instance into the database, along with location information if a new one was created and return true if successful, false if not.
  536.          * Will automatically detect whether it's a new or existing event.
  537.          * @return boolean
  538.          */
  539.         function save(){
  540.                 global $wpdb, $current_user, $blog_id;
  541.                 if( !$this->can_manage('edit_events', 'edit_others_events') && !( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) ){
  542.                         //unless events can be submitted by an anonymous user (and this is a new event), user must have permissions.
  543.                         return apply_filters('em_event_save', false, $this);
  544.                 }
  545.                 remove_action('save_post',array('EM_Event_Post_Admin','save_post'),10,1); //disable the default save post action, we'll do it manually this way
  546.                 do_action('em_event_save_pre', $this);
  547.                 $post_array = array();
  548.                 //Deal with updates to an event
  549.                 if( !empty($this->post_id) ){
  550.                         //get the full array of post data so we don't overwrite anything.
  551.                         if( !empty($this->blog_id) && is_multisite() ){
  552.                                 $post_array = (array) get_blog_post($this->blog_id, $this->post_id);
  553.                         }else{
  554.                                 $post_array = (array) get_post($this->post_id);
  555.                         }
  556.                 }
  557.                 //Overwrite new post info
  558.                 $post_array['post_type'] = ($this->recurrence && get_option('dbem_recurrence_enabled')) ? 'event-recurring':EM_POST_TYPE_EVENT;
  559.                 $post_array['post_title'] = $this->event_name;
  560.                 $post_array['post_content'] = $this->post_content;
  561.                 //decide on post status
  562.                 if( empty($this->force_status) ){
  563.                         if( count($this->errors) == 0 ){
  564.                                 $post_array['post_status'] = ( $this->can_manage('publish_events','publish_events') ) ? 'publish':'pending';
  565.                         }else{
  566.                                 $post_array['post_status'] = 'draft';
  567.                         }
  568.                 }else{
  569.                     $post_array['post_status'] = $this->force_status;
  570.                 }
  571.                 //anonymous submission only
  572.                 if( !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') && empty($this->event_id) ){
  573.                         $post_array['post_author'] = get_option('dbem_events_anonymous_user');
  574.                         if( !is_numeric($post_array['post_author']) ) $post_array['post_author'] = 0;
  575.                 }
  576.                 //Save post and continue with meta
  577.                 $post_id = wp_insert_post($post_array);
  578.                 $post_save = false;
  579.                 $meta_save = false;
  580.                 if( !is_wp_error($post_id) && !empty($post_id) ){
  581.                         $post_save = true;
  582.                         //refresh this event with wp post info we'll put into the db
  583.                         $post_data = get_post($post_id);
  584.                         $this->post_id = $post_id;
  585.                         $this->event_slug = $post_data->post_name;
  586.                         $this->event_owner = $post_data->post_author;
  587.                         $this->post_status = $post_data->post_status;
  588.                         $this->get_status();
  589.                         //Categories? note that categories will soft-fail, so no errors
  590.                         $this->get_categories()->event_id = $this->event_id;
  591.                         $this->categories->post_id = $this->post_id;
  592.                         $this->categories->save();
  593.                         //anonymous submissions should save this information
  594.                         if( !empty($this->event_owner_anonymous) ){
  595.                                 update_post_meta($this->post_id, '_event_owner_anonymous', 1);
  596.                                 update_post_meta($this->post_id, '_event_owner_name', $this->event_owner_name);
  597.                                 update_post_meta($this->post_id, '_event_owner_email', $this->event_owner_email);
  598.                         }
  599.                         //save the image
  600.                         $this->image_upload();
  601.                         //now save the meta
  602.                         $meta_save = $this->save_meta();
  603.                         $image_save = (count($this->errors) == 0); //whilst it might not be an image save that fails, we can know something went wrong
  604.                 }
  605.                 $result = $meta_save && $post_save && $image_save;
  606.                 $previous_status = $this->previous_status;
  607.                 if($result) $this->load_postdata($post_data, $blog_id); //reload post info
  608.                 $this->previous_status = $previous_status;
  609.                 //do a dirty update for location too if it's not published
  610.                 if( $this->is_published() && !empty($this->location_id) ){
  611.                         $EM_Location = $this->get_location();
  612.                         if( $EM_Location->location_status !== 1 ){
  613.                                 //let's also publish the location
  614.                                 $EM_Location->set_status(1, true);
  615.                         }
  616.                 }
  617.                 return apply_filters('em_event_save', $result, $this);
  618.         }
  619.        
  620.         function save_meta(){
  621.                 global $wpdb;
  622.                 if( ( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) || $this->can_manage('edit_events', 'edit_others_events') ){
  623.                         do_action('em_event_save_meta_pre', $this);
  624.                         //first save location
  625.                         if( empty($this->location_id) && !($this->location_id === 0 && !get_option('dbem_require_location',true)) ){
  626.                                 if( !$this->get_location()->save() ){ //soft fail
  627.                                         global $EM_Notices;
  628.                                         if( !empty($this->get_location()->location_id) ){
  629.                                                 $EM_Notices->add_error( __('There were some errors saving your location.','dbem').' '.sprintf(__('It will not be displayed on the website listings, to correct this you must <a href="%s">edit your location</a> directly.'),$this->get_location()->output('#_LOCATIONEDITURL')), true);
  630.                                         }else{
  631.                                                 $this->get_location()->set_status(null);
  632.                                                 $EM_Notices->add_error( __('There were some errors saving your location.'), true);
  633.                                         }
  634.                                 }
  635.                                 if( !empty($this->location->location_id) ){ //only case we don't use get_location(), since it will fail as location has an id, whereas location_id isn't set in this object
  636.                                         $this->location_id = $this->location->location_id;
  637.                                 }
  638.                         }
  639.                         //Update Post Meta
  640.                         foreach($this->fields as $key => $field_info){
  641.                                 if( !in_array($key, $this->post_fields) && $key != 'event_attributes' ){
  642.                                         update_post_meta($this->post_id, '_'.$key, $this->$key);
  643.                                 }elseif($key == 'event_attributes'){
  644.                                         //attributes get saved as individual keys
  645.                                         foreach($this->event_attributes as $event_attribute_key => $event_attribute){
  646.                                                 if( !empty($event_attribute) ){
  647.                                                         update_post_meta($this->post_id, $event_attribute_key, $event_attribute);
  648.                                                 }else{
  649.                                                         delete_post_meta($this->post_id, $event_attribute_key);
  650.                                                 }
  651.                                         }
  652.                                 }
  653.                         }
  654.                         //update timestampes
  655.                         update_post_meta($this->post_id, '_start_ts', str_pad($this->start, 10, 0, STR_PAD_LEFT));
  656.                         update_post_meta($this->post_id, '_end_ts', str_pad($this->end, 10, 0, STR_PAD_LEFT));
  657.                         //sort out event status                
  658.                         $result = count($this->errors) == 0;
  659.                         $this->get_status();
  660.                         $this->event_status = ($result) ? $this->event_status:null; //set status at this point, it's either the current status, or if validation fails, null
  661.                         //Save to em_event table
  662.                         $event_array = $this->to_array(true);
  663.                         unset($event_array['event_id']);
  664.                         //decide whether or not event is private at this point
  665.                         $event_array['event_private'] = ( $this->post_status == 'private' ) ? 1:0;
  666.                         //save event_attributes just in case
  667.                         $event_array['event_attributes'] = serialize($this->event_attributes);
  668.                         //check if event truly exists, meaning the event_id is actually a valid event id
  669.                         if( !empty($this->event_id) ){
  670.                                 $blog_condition = '';
  671.                                 if( EM_MS_GLOBAL ){
  672.                                     if( is_main_site() ){
  673.                                         $blog_condition = " AND (blog_id='".get_current_blog_id()."' OR blog_id IS NULL)";
  674.                                     }else{
  675.                                                 $blog_condition = " AND blog_id='".get_current_blog_id()."' ";
  676.                                     }
  677.                                 }
  678.                                 $event_truly_exists = $wpdb->get_var('SELECT post_id FROM '.EM_EVENTS_TABLE." WHERE event_id={$this->event_id}".$blog_condition) == $this->post_id;
  679.                         }else{
  680.                                 $event_truly_exists = false;
  681.                         }
  682.                         //save all the meta
  683.                         if( empty($this->event_id) || !$event_truly_exists ){
  684.                                 $this->previous_status = 0; //for sure this was previously status 0
  685.                                 $this->event_date_created = current_time('mysql');
  686.                                 if ( !$wpdb->insert(EM_EVENTS_TABLE, $event_array) ){
  687.                                         $this->add_error( sprintf(__('Something went wrong saving your %s to the index table. Please inform a site administrator about this.','dbem'),__('event','dbem')));
  688.                                 }else{
  689.                                         //success, so link the event with the post via an event id meta value for easy retrieval
  690.                                         $this->event_id = $wpdb->insert_id;
  691.                                         update_post_meta($this->post_id, '_event_id', $this->event_id);
  692.                                         $this->feedback_message = sprintf(__('Successfully saved %s','dbem'),__('Event','dbem'));
  693.                                         $just_added_event = true; //make an easy hook
  694.                                         do_action('em_event_save_new', $this);
  695.                                 }
  696.                         }else{
  697.                             $event_array['post_content'] = $this->post_content; //in case the content was removed, which is acceptable
  698.                                 $this->previous_status = $this->get_previous_status();
  699.                                 $this->event_date_modified = $event_array['event_date_modified'] = current_time('mysql');
  700.                                 if ( $wpdb->update(EM_EVENTS_TABLE, $event_array, array('event_id'=>$this->event_id) ) === false ){
  701.                                         $this->add_error( sprintf(__('Something went wrong updating your %s to the index table. Please inform a site administrator about this.','dbem'),__('event','dbem')));                  
  702.                                 }else{
  703.                                         //Also set the status here if status != previous status
  704.                                         if( $this->previous_status != $this->get_status()){
  705.                                                 $status_value = $this->get_status(true);
  706.                                                 $wpdb->query('UPDATE '.EM_EVENTS_TABLE." SET event_status=$status_value WHERE event_id=".$this->event_id);
  707.                                         }
  708.                                         $this->feedback_message = sprintf(__('Successfully saved %s','dbem'),__('Event','dbem'));
  709.                                 }              
  710.                         }
  711.                         //Add/Delete Tickets
  712.                         if($this->event_rsvp == 0){
  713.                                 $this->get_bookings()->delete();
  714.                         }else{
  715.                                 if( !$this->get_bookings()->get_tickets()->save() ){
  716.                                         $this->add_error( $this->get_bookings()->get_tickets()->get_errors() );
  717.                                 }
  718.                         }
  719.                         $result = count($this->errors) == 0;
  720.                         //If we're saving event categories in MS Global mode, we'll add them here, saving by term id (cat ids are gone now)
  721.                         if( EM_MS_GLOBAL && !is_main_site() ){
  722.                                 $this->get_categories()->save(); //it'll know what to do
  723.                         }elseif( EM_MS_GLOBAL ){
  724.                                 $this->get_categories()->save_index(); //just save to index, we assume cats are saved in $this->save();
  725.                         }
  726.                         //build recurrences if needed
  727.                         if( $this->is_recurring() && $result && $this->is_published() ){ //only save events if recurring event validates and is published
  728.                                 if( !$this->save_events() ){ //only save if post is 'published'
  729.                                         $this->add_error(__ ( 'Something went wrong with the recurrence update...', 'dbem' ). __ ( 'There was a problem saving the recurring events.', 'dbem' ));
  730.                                 }
  731.                         }
  732.                         if( !empty($just_added_event) ){
  733.                                 do_action('em_event_added', $this);
  734.                         }
  735.                 }
  736.                 $this->compat_keys();
  737.                 return apply_filters('em_event_save_meta', count($this->errors) == 0, $this);
  738.         }
  739.        
  740.         /**
  741.          * Duplicates this event and returns the duplicated event. Will return false if there is a problem with duplication.
  742.          * @return EM_Event
  743.          */
  744.         function duplicate(){
  745.                 global $wpdb, $EZSQL_ERROR;
  746.                 //First, duplicate.
  747.                 if( $this->can_manage('edit_events','edit_others_events') ){
  748.                         $EM_Event = clone $this;
  749.                         $EM_Event->get_categories(); //before we remove event/post ids
  750.                         $EM_Event->get_bookings()->get_tickets(); //in case this wasn't loaded and before we reset ids
  751.                         $EM_Event->event_id = null;
  752.                         $EM_Event->post_id = null;
  753.                         $EM_Event->ID = null;
  754.                         $EM_Event->post_name = '';
  755.                         $EM_Event->location_id = (empty($EM_Event->location_id)  && !get_option('dbem_require_location')) ? 0:$EM_Event->location_id;
  756.                         $EM_Event->get_bookings()->event_id = null;
  757.                         $EM_Event->get_bookings()->get_tickets()->event_id = null;
  758.                         //if bookings reset ticket ids and duplicate tickets
  759.                         foreach($EM_Event->get_bookings()->get_tickets()->tickets as $EM_Ticket){
  760.                                 $EM_Ticket->ticket_id = null;
  761.                                 $EM_Ticket->event_id = null;
  762.                         }
  763.                         do_action('em_event_duplicate_pre', $EM_Event);
  764.                         $EM_Event->duplicated = true;
  765.                         $EM_Event->force_status = 'draft';
  766.                         if( $EM_Event->save() ){
  767.                                 $EM_Event->feedback_message = sprintf(__("%s successfully duplicated.", 'dbem'), __('Event','dbem'));
  768.                                 //other non-EM post meta inc. featured image
  769.                                 $event_meta = $this->get_event_meta($this->blog_id);
  770.                                 $event_meta['_event_approvals_count'] = 0; //reset this counter for new event
  771.                                 $event_meta_inserts = array();
  772.                                 //Get custom fields and post meta - adapted from $this->load_post_meta()
  773.                                 foreach($event_meta as $event_meta_key => $event_meta_vals){
  774.                                         if($event_meta_key[0] == '_' && is_array($event_meta_vals)){
  775.                                             $field_name = substr($event_meta_key, 1);
  776.                                                 if($field_name != 'event_attributes' && !array_key_exists($field_name, $this->fields) && !in_array($field_name, array('edit_last', 'edit_lock', 'event_owner_name','event_owner_anonymous','event_owner_email')) ){
  777.                                                         foreach($event_meta_vals as $event_meta_val){
  778.                                                             $event_meta_inserts[] = "({$EM_Event->post_id}, '{$event_meta_key}', '{$event_meta_val}')";
  779.                                                         }
  780.                                                 }
  781.                                         }
  782.                                 }
  783.                                 //save in one SQL statement
  784.                                 if( !empty($event_meta_inserts) ){
  785.                                         $wpdb->query('INSERT INTO '.$wpdb->postmeta." (post_id, meta_key, meta_value) VALUES ".implode(', ', $event_meta_inserts));
  786.                                 }
  787.                                 //set event to draft status
  788.                                 return apply_filters('em_event_duplicate', $EM_Event, $this);
  789.                         }
  790.                 }
  791.                 //TODO add error notifications for duplication failures.
  792.                 return apply_filters('em_event_duplicate', false, $this);;
  793.         }
  794.        
  795.         /**
  796.          * Delete whole event, including bookings, tickets, etc.
  797.          * @return boolean
  798.          */
  799.         function delete($force_delete = false){ //atm wp seems to force cp deletions anyway
  800.                 global $wpdb;
  801.                 if( $this->can_manage('delete_events', 'delete_others_events') ){
  802.                     if( !is_admin() ){
  803.                                 include_once('em-event-post-admin.php');
  804.                                 if( !defined('EM_EVENT_DELETE_INCLUDE') ){
  805.                                         EM_Event_Post_Admin::init();
  806.                                         EM_Event_Recurring_Post_Admin::init();
  807.                                         define('EM_EVENT_DELETE_INCLUDE',true);
  808.                                 }
  809.                     }
  810.                     do_action('em_event_delete_pre', $this);
  811.                         if( $force_delete ){
  812.                                 $result = wp_delete_post($this->post_id,$force_delete);
  813.                         }else{
  814.                                 $result = wp_trash_post($this->post_id);
  815.                         }
  816.                 }else{
  817.                         $result = false;
  818.                 }
  819.                 //print_r($result); echo "|"; print_r($result_meta); die('DELETING');
  820.                 return apply_filters('em_event_delete', $result !== false, $this);
  821.         }
  822.        
  823.         function delete_meta(){
  824.                 global $wpdb;
  825.                 $result = false;
  826.                 if( $this->can_manage('delete_events', 'delete_others_events') ){
  827.                         do_action('em_event_delete_meta_event_pre', $this);
  828.                         $result = $wpdb->query ( $wpdb->prepare("DELETE FROM ". EM_EVENTS_TABLE ." WHERE event_id=%d", $this->event_id) );
  829.                         if( $result !== false ){
  830.                                 $this->delete_bookings();
  831.                                 $this->delete_tickets();
  832.                                 //Delete the recurrences then this recurrence event
  833.                                 if( $this->is_recurring() ){
  834.                                         $result = $this->delete_events(); //was true at this point, so false if fails
  835.                                 }
  836.                                 //Delete categories from meta if in MS global mode
  837.                                 if( EM_MS_GLOBAL ){
  838.                                         $wpdb->query('DELETE FROM '.EM_META_TABLE.' WHERE object_id='.$this->event_id." AND meta_key='event-category'");
  839.                                 }
  840.                         }
  841.                 }
  842.                 return apply_filters('em_event_delete_meta', $result !== false, $this);
  843.         }
  844.        
  845.         /**
  846.          * Shortcut function for $this->get_bookings()->delete(), because using the EM_Bookings requires loading previous bookings, which isn't neceesary.
  847.          */
  848.         function delete_bookings(){
  849.                 global $wpdb;
  850.                 do_action('em_event_delete_bookings_pre', $this);
  851.                 $result = false;
  852.                 if( $this->can_manage('manage_bookings','manage_others_bookings') ){
  853.                         $result_bt = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id IN (SELECT booking_id FROM ".EM_BOOKINGS_TABLE." WHERE event_id=%d)", $this->event_id) );
  854.                         $result = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_BOOKINGS_TABLE." WHERE event_id=%d", $this->event_id) );
  855.                 }
  856.                 return apply_filters('em_event_delete_bookings', $result !== false && $result_bt !== false, $this);
  857.         }
  858.        
  859.         /**
  860.          * Shortcut function for $this->get_bookings()->delete(), because using the EM_Bookings requires loading previous bookings, which isn't neceesary.
  861.          */
  862.         function delete_tickets(){
  863.                 global $wpdb;
  864.                 do_action('em_event_delete_tickets_pre', $this);
  865.                 $result = false;
  866.                 if( $this->can_manage('manage_bookings','manage_others_bookings') ){
  867.                         $result_bt = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE ticket_id IN (SELECT ticket_id FROM ".EM_TICKETS_TABLE." WHERE event_id=%d)", $this->event_id) );
  868.                         $result = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_TABLE." WHERE event_id=%d", $this->event_id) );
  869.                 }
  870.                 return apply_filters('em_event_delete_tickets', $result, $this);
  871.         }
  872.        
  873.         /**
  874.          * Change the status of the event. This will save to the Database too.
  875.          * @param int $status
  876.          * @param boolean $set_post_status
  877.          * @return string
  878.          */
  879.         function set_status($status, $set_post_status = false){
  880.                 global $wpdb;
  881.                 if($status === null){
  882.                         $set_status='NULL';
  883.                         if($set_post_status){
  884.                                 //if the post is trash, don't untrash it!
  885.                                 $wpdb->update( $wpdb->posts, array( 'post_status' => 'draft' ), array( 'ID' => $this->post_id ) );
  886.                                 $this->post_status = 'draft';
  887.                         }
  888.                 }else{
  889.                         $set_status = $status ? 1:0;
  890.                         if($set_post_status){
  891.                                 if($this->post_status == 'pending'){
  892.                                         $this->post_name = sanitize_title($this->post_title);
  893.                                 }
  894.                                 $this->post_status = $set_status ? 'publish':'pending';
  895.                                 $wpdb->update( $wpdb->posts, array( 'post_status' => $this->post_status, 'post_name' => $this->post_name ), array( 'ID' => $this->post_id ) );
  896.                         }              
  897.                 }
  898.                 $this->previous_status = $this->get_previous_status();
  899.                 $result = $wpdb->query("UPDATE ".EM_EVENTS_TABLE." SET event_status=$set_status, event_slug='{$this->post_name}' WHERE event_id=".$this->event_id);
  900.                 $this->get_status(); //reload status
  901.                 return apply_filters('em_event_set_status', $result !== false, $status, $this);
  902.         }
  903.        
  904.         function is_published(){
  905.                 return apply_filters('em_event_is_published', ($this->post_status == 'publish' || $this->post_status == 'private'), $this);
  906.         }
  907.        
  908.         function get_status($db = false){
  909.                 switch( $this->post_status ){
  910.                         case 'private':
  911.                                 $this->event_private = 1;
  912.                                 $this->event_status = $status = 1;
  913.                                 break;
  914.                         case 'publish':
  915.                                 $this->event_private = 0;
  916.                                 $this->event_status = $status = 1;
  917.                                 break;
  918.                         case 'pending':
  919.                                 $this->event_private = 0;
  920.                                 $this->event_status = $status = 0;
  921.                                 break;
  922.                         default: //draft or unknown
  923.                                 $this->event_private = 0;
  924.                                 $status = $db ? 'NULL':null;
  925.                                 $this->event_status = null;
  926.                                 break;
  927.                 }
  928.                 return $status;
  929.         }
  930.        
  931.         function get_previous_status(){
  932.                 global $wpdb;
  933.                 return $wpdb->get_var('SELECT event_status FROM '.EM_EVENTS_TABLE.' WHERE event_id='.$this->event_id); //get status from db, not post_status, as posts get saved quickly
  934.         }
  935.        
  936.         /**
  937.          * Returns an EM_Categories object of the EM_Event instance.
  938.          * @return EM_Categories
  939.          */
  940.         function get_categories() {
  941.                 if( empty($this->categories) ){
  942.                         $this->categories = new EM_Categories($this);
  943.                 }elseif(empty($this->categories->event_id)){
  944.                         $this->categories->event_id = $this->event_id;
  945.                         $this->categories->post_id = $this->post_id;                   
  946.                 }
  947.                 return apply_filters('em_event_get_categories', $this->categories, $this);
  948.         }
  949.        
  950.         /**
  951.          * Returns the location object this event belongs to.
  952.          * @return EM_Location
  953.          */
  954.         function get_location() {
  955.                 global $EM_Location;
  956.                 if( is_object($EM_Location) && $EM_Location->location_id == $this->location_id ){
  957.                         $this->location = $EM_Location;
  958.                 }else{
  959.                         if( !is_object($this->location) || $this->location->location_id != $this->location_id ){
  960.                                 $this->location = em_get_location($this->location_id);
  961.                         }
  962.                 }
  963.                 return $this->location;
  964.         }      
  965.        
  966.         /**
  967.          * Returns the location object this event belongs to.
  968.          * @return EM_Person
  969.          */    
  970.         function get_contact(){
  971.                 if( !is_object($this->contact) ){
  972.                         $this->contact = new EM_Person($this->event_owner);
  973.                         //if this is anonymous submission, change contact email and name
  974.                         if( $this->event_owner_anonymous ){
  975.                                 $this->contact->user_email = $this->event_owner_email;
  976.                                 $name = explode(' ',$this->event_owner_name);
  977.                                 $first_name = array_shift($name);
  978.                                 $last_name = (count($name) > 0) ? implode(' ',$name):'';
  979.                                 $this->contact->user_firstname = $this->contact->first_name = $first_name;
  980.                                 $this->contact->user_lastname = $this->contact->last_name = $last_name;
  981.                         }
  982.                 }
  983.                 return $this->contact;
  984.         }
  985.        
  986.         /**
  987.          * Retrieve and save the bookings belonging to instance. If called again will return cached version, set $force_reload to true to create a new EM_Bookings object.
  988.          * @param boolean $force_reload
  989.          * @return EM_Bookings
  990.          */
  991.         function get_bookings( $force_reload = false ){
  992.                 if( get_option('dbem_rsvp_enabled') ){
  993.                         if( (!$this->bookings || $force_reload) ){
  994.                                 $this->bookings = new EM_Bookings($this);
  995.                         }
  996.                         $this->bookings->event_id = $this->event_id; //always refresh event_id
  997.                 }else{
  998.                         return new EM_Bookings();
  999.                 }
  1000.                 //TODO for some reason this returned instance doesn't modify the original, e.g. try $this->get_bookings()->add($EM_Booking) and see how $this->bookings->feedback_message doesn't change
  1001.                 return apply_filters('em_event_get_bookings', $this->bookings, $this);
  1002.         }
  1003.        
  1004.         /**
  1005.          * Get the tickets related to this event.
  1006.          * @param boolean $force_reload
  1007.          * @return EM_Tickets
  1008.          */
  1009.         function get_tickets( $force_reload = false ){
  1010.                 return $this->get_bookings($force_reload)->get_tickets();
  1011.         }
  1012.        
  1013.         /**
  1014.          * Gets number of spaces in this event, dependent on ticket spaces or hard limit, whichever is smaller.
  1015.          * @param boolean $force_refresh
  1016.          * @return int
  1017.          */
  1018.         function get_spaces($force_refresh=false){
  1019.                 return $this->get_bookings()->get_spaces($force_refresh);
  1020.         }
  1021.        
  1022.         /*
  1023.          * Extends the default EM_Object function by switching blogs as needed if in MS Global mode  
  1024.          * @param string $size
  1025.          * @return string
  1026.          * @see EM_Object::get_image_url()
  1027.          */
  1028.         function get_image_url($size = 'full'){
  1029.             if( EM_MS_GLOBAL && get_current_blog_id() != $this->blog_id ){
  1030.                 switch_to_blog($this->blog_id);
  1031.                 $switch_back = true;
  1032.             }
  1033.                 $return = parent::get_image_url($size);
  1034.                 if( !empty($switch_back) ){ restore_current_blog(); }
  1035.                 return $return;
  1036.         }
  1037.        
  1038.         function get_edit_reschedule_url(){
  1039.                 if( $this->is_recurrence() ){
  1040.                         $EM_Event = em_get_event($this->recurrence_id);
  1041.                         return $EM_Event->get_edit_url();
  1042.                 }
  1043.         }
  1044.        
  1045.         function get_edit_url(){
  1046.                 if( $this->can_manage('edit_events','edit_others_events') ){
  1047.                         if( EM_MS_GLOBAL && get_site_option('dbem_ms_global_events_links') && !empty($this->blog_id) && is_main_site() && $this->blog_id != get_current_blog_id() ){
  1048.                                 if( get_blog_option($this->blog_id, 'dbem_edit_events_page') ){
  1049.                                         $link = em_add_get_params(get_permalink(get_blog_option($this->blog_id, 'dbem_edit_events_page')), array('action'=>'edit','event_id'=>$this->event_id), false);
  1050.                                 }
  1051.                                 if( empty($link))
  1052.                                         $link = get_admin_url($this->blog_id, "post.php?post={$this->post_id}&action=edit");
  1053.                         }else{
  1054.                                 if( get_option('dbem_edit_events_page') && !is_admin() ){
  1055.                                         $link = em_add_get_params(get_permalink(get_option('dbem_edit_events_page')), array('action'=>'edit','event_id'=>$this->event_id), false);
  1056.                                 }
  1057.                                 if( empty($link))
  1058.                                         $link = admin_url()."post.php?post={$this->post_id}&action=edit";
  1059.                         }
  1060.                         return apply_filters('em_event_get_edit_url', $link, $this);
  1061.                 }
  1062.         }
  1063.        
  1064.         function get_bookings_url(){
  1065.                 if( get_option('dbem_edit_bookings_page') && (!is_admin() || !empty($_REQUEST['is_public'])) ){
  1066.                         $my_bookings_page = get_permalink(get_option('dbem_edit_bookings_page'));
  1067.                         $bookings_link = em_add_get_params($my_bookings_page, array('event_id'=>$this->event_id), false);
  1068.                 }else{
  1069.                         if( is_multisite() && $this->blog_id != get_current_blog_id() ){
  1070.                                 $bookings_link = get_admin_url($this->blog_id, 'edit.php?post_type='.EM_POST_TYPE_EVENT."&page=events-manager-bookings&event_id=".$this->event_id);
  1071.                         }else{
  1072.                                 $bookings_link = EM_ADMIN_URL. "&page=events-manager-bookings&event_id=".$this->event_id;
  1073.                         }
  1074.                 }
  1075.                 return apply_filters('em_event_get_bookings_url', $bookings_link, $this);
  1076.         }
  1077.        
  1078.         function get_permalink(){
  1079.                 if( EM_MS_GLOBAL ){
  1080.                         if( get_site_option('dbem_ms_global_events_links') && !empty($this->blog_id) && $this->blog_id != get_current_blog_id() ){
  1081.                                 //linking directly to the blog
  1082.                                 $event_link = get_blog_permalink( $this->blog_id, $this->post_id);
  1083.                         }elseif( !empty($this->blog_id) && is_main_site() && $this->blog_id != get_current_blog_id() ){
  1084.                                 if( get_option('dbem_events_page') ){
  1085.                                         $event_link = trailingslashit(get_permalink(get_option('dbem_events_page')).get_site_option('dbem_ms_events_slug',EM_EVENT_SLUG).'/'.$this->event_slug.'-'.$this->event_id);
  1086.                                 }else{
  1087.                                         $event_link = trailingslashit(home_url()).EM_POST_TYPE_EVENT_SLUG.'/'.get_site_option('dbem_ms_events_slug',EM_EVENT_SLUG).'/'.$this->event_slug.'-'.$this->event_id;
  1088.                                 }
  1089.                         }
  1090.                 }
  1091.                 if( empty($event_link) ){
  1092.                         $event_link = get_post_permalink($this->post_id);
  1093.                 }
  1094.                 return apply_filters('em_event_get_permalink', $event_link, $this);
  1095.         }
  1096.        
  1097.         function get_ical_url(){
  1098.                 global $wp_rewrite;
  1099.                 if( !empty($wp_rewrite) && $wp_rewrite->using_permalinks() ){
  1100.                         return trailingslashit($this->get_permalink()).'ical/';
  1101.                 }else{
  1102.                         return em_add_get_params($this->get_permalink(), array('ical'=>1));
  1103.                 }
  1104.         }
  1105.        
  1106.         function is_free( $now = false ){
  1107.                 $free = true;
  1108.                 foreach($this->get_tickets() as $EM_Ticket){
  1109.                     /* @var $EM_Ticket EM_Ticket */
  1110.                         if( $EM_Ticket->get_price() > 0 ){
  1111.                                 if( !$now || $EM_Ticket->is_available() ){     
  1112.                                     $free = false;
  1113.                                 }
  1114.                         }
  1115.                 }
  1116.                 return apply_filters('em_event_is_free',$free,$this);
  1117.         }
  1118.        
  1119.         /**
  1120.          * Will output a single event format of this event.
  1121.          * Equivalent of calling EM_Event::output( get_option ( 'dbem_single_event_format' ) )
  1122.          * @param string $target
  1123.          * @return string
  1124.          */
  1125.         function output_single($target='html'){
  1126.                 $format = get_option ( 'dbem_single_event_format' );
  1127.                 return apply_filters('em_event_output_single', $this->output($format, $target), $this, $target);
  1128.         }
  1129.        
  1130.         /**
  1131.          * Will output a event in the format passed in $format by replacing placeholders within the format.
  1132.          * @param string $format
  1133.          * @param string $target
  1134.          * @return string
  1135.          */    
  1136.         function output($format, $target="html") {     
  1137.                 $event_string = $format;
  1138.                 //Time place holder that doesn't show if empty.
  1139.                 //TODO add filter here too
  1140.                 preg_match_all('/#@?_\{[^}]+\}/', $format, $results);
  1141.                 foreach($results[0] as $result) {
  1142.                         if(substr($result, 0, 3 ) == "#@_"){
  1143.                                 $date = 'end_date';
  1144.                                 $offset = 4;
  1145.                         }else{
  1146.                                 $date = 'start_date';
  1147.                                 $offset = 3;
  1148.                         }
  1149.                         if( $date == 'end_date' && $this->event_end_date == $this->event_start_date ){
  1150.                                 $replace = __( apply_filters('em_event_output_placeholder', '', $this, $result, $target) );
  1151.                         }else{
  1152.                                 $replace = __( apply_filters('em_event_output_placeholder', mysql2date(substr($result, $offset, (strlen($result)-($offset+1)) ), $this->$date), $this, $result, $target) );
  1153.                         }
  1154.                         $event_string = str_replace($result,$replace,$event_string );
  1155.                 }
  1156.                 //This is for the custom attributes
  1157.                 preg_match_all('/#_ATT\{([^}]+)\}(\{([^}]+)\})?/', $format, $results);
  1158.                 $attributes = em_get_attributes();
  1159.                 foreach($results[0] as $resultKey => $result) {
  1160.                         //Strip string of placeholder and just leave the reference
  1161.                         $attRef = substr( substr($result, 0, strpos($result, '}')), 6 );
  1162.                         $attString = '';
  1163.                         if( is_array($this->event_attributes) && array_key_exists($attRef, $this->event_attributes) ){
  1164.                                 $attString = $this->event_attributes[$attRef];
  1165.                         }elseif( !empty($results[3][$resultKey]) ){
  1166.                                 //Check to see if we have a second set of braces;
  1167.                                 $attString = $results[3][$resultKey];
  1168.                         }elseif( !empty($attributes['values'][$attRef][0]) ){
  1169.                             $attString = $attributes['values'][$attRef][0];
  1170.                         }
  1171.                         $attString = apply_filters('em_event_output_placeholder', $attString, $this, $result, $target);
  1172.                         $event_string = str_replace($result, $attString ,$event_string );
  1173.                 }
  1174.                 //First let's do some conditional placeholder removals
  1175.                 for ($i = 0 ; $i < EM_CONDITIONAL_RECURSIONS; $i++){ //you can add nested recursions by modifying this setting in your wp_options table
  1176.                         preg_match_all('/\{([a-zA-Z0-9_]+)\}(.+?)\{\/\1\}/s', $event_string, $conditionals);
  1177.                         if( count($conditionals[0]) > 0 ){
  1178.                                 //Check if the language we want exists, if not we take the first language there
  1179.                                 foreach($conditionals[1] as $key => $condition){
  1180.                                         $show_condition = false;
  1181.                                         if ($condition == 'has_bookings') {
  1182.                                                 //check if there's a booking, if not, remove this section of code.
  1183.                                                 $show_condition = ($this->event_rsvp && get_option('dbem_rsvp_enabled'));
  1184.                                         }elseif ($condition == 'no_bookings') {
  1185.                                                 //check if there's a booking, if not, remove this section of code.
  1186.                                                 $show_condition = (!$this->event_rsvp && get_option('dbem_rsvp_enabled'));
  1187.                                         }elseif ($condition == 'no_location'){
  1188.                                                 //does this event have a valid location?
  1189.                                                 $show_condition = ( empty($this->location_id) || !$this->get_location()->location_status );
  1190.                                         }elseif ($condition == 'has_location'){
  1191.                                                 //does this event have a valid location?
  1192.                                                 $show_condition = ( !empty($this->location_id) && $this->get_location()->location_status );
  1193.                                         }elseif ($condition == 'has_image'){
  1194.                                                 //does this event have an image?
  1195.                                                 $show_condition = ( $this->get_image_url() != '' );
  1196.                                         }elseif ($condition == 'no_image'){
  1197.                                                 //does this event have an image?
  1198.                                                 $show_condition = ( $this->get_image_url() == '' );
  1199.                                         }elseif ($condition == 'has_time'){
  1200.                                                 //are the booking times different and not an all-day event
  1201.                                                 $show_condition = ( $this->event_start_time != $this->event_end_time && !$this->event_all_day );
  1202.                                         }elseif ($condition == 'no_time'){
  1203.                                                 //are the booking times exactly the same and it's not an all-day event.
  1204.                                                 $show_condition = ( $this->event_start_time == $this->event_end_time && !$this->event_all_day );
  1205.                                         }elseif ($condition == 'all_day'){
  1206.                                                 //is it an all day event
  1207.                                                 $show_condition = !empty($this->event_all_day);
  1208.                                         }elseif ($condition == 'logged_in'){
  1209.                                                 //user is logged in
  1210.                                                 $show_condition = is_user_logged_in();
  1211.                                         }elseif ($condition == 'not_logged_in'){
  1212.                                                 //not logged in
  1213.                                                 $show_condition = !is_user_logged_in();
  1214.                                         }elseif ($condition == 'has_spaces'){
  1215.                                                 //is it an all day event
  1216.                                                 $show_condition = $this->event_rsvp && $this->get_bookings()->get_available_spaces() > 0;
  1217.                                         }elseif ($condition == 'fully_booked'){
  1218.                                                 //is it an all day event
  1219.                                                 $show_condition = $this->event_rsvp && $this->get_bookings()->get_available_spaces() <= 0;
  1220.                                         }elseif ($condition == 'is_free' || $condition == 'is_free_now'){
  1221.                                                 //is it a free day event, if _now then free right now
  1222.                                                 $show_condition = !$this->event_rsvp || $this->is_free( $condition == 'is_free_now' );
  1223.                                         }elseif ($condition == 'not_free' || $condition == 'not_free_now'){
  1224.                                                 //is it a paid event, if _now then paid right now
  1225.                                                 $show_condition = $this->event_rsvp && !$this->is_free( $condition == 'not_free_now' );
  1226.                                         }elseif ($condition == 'is_long'){
  1227.                                                 //is it an all day event
  1228.                                                 $show_condition = $this->event_start_date != $this->event_end_date;
  1229.                                         }elseif ($condition == 'not_long'){
  1230.                                                 //is it an all day event
  1231.                                                 $show_condition = $this->event_start_date == $this->event_end_date;
  1232.                                         }elseif ($condition == 'is_past'){
  1233.                                                 //if event is past
  1234.                                                 $show_condition = $this->start <= current_time('timestamp');
  1235.                                         }elseif ($condition == 'is_future'){
  1236.                                                 //if event is upcoming
  1237.                                                 $show_condition = $this->start > current_time('timestamp');
  1238.                                         }elseif ($condition == 'is_recurrence'){
  1239.                                                 //if event is a recurrence
  1240.                                                 $show_condition = $this->is_recurrence();
  1241.                                         }elseif ($condition == 'not_recurrence'){
  1242.                                                 //if event is not a recurrence
  1243.                                                 $show_condition = !$this->is_recurrence();
  1244.                                         }elseif ($condition == 'is_private'){
  1245.                                                 //if event is a recurrence
  1246.                                                 $show_condition = $this->event_private == 1;
  1247.                                         }elseif ($condition == 'not_private'){
  1248.                                                 //if event is not a recurrence
  1249.                                                 $show_condition = $this->event_private == 0;
  1250.                                         }elseif ( preg_match('/^has_category_([a-zA-Z0-9_\-]+)$/', $condition, $category_match)){
  1251.                                             //event is in this category
  1252.                                             $show_condition = has_term($category_match[1], EM_TAXONOMY_CATEGORY, $this->post_id);
  1253.                                         }elseif ( preg_match('/^no_category_([a-zA-Z0-9_\-]+)$/', $condition, $category_match)){
  1254.                                             //event is NOT in this category
  1255.                                             $show_condition = !has_term($category_match[1], EM_TAXONOMY_CATEGORY, $this->post_id);
  1256.                                         }elseif ( preg_match('/^has_tag_([a-zA-Z0-9_\-]+)$/', $condition, $tag_match)){
  1257.                                             //event has this tag
  1258.                                             $show_condition = has_term($tag_match[1], EM_TAXONOMY_TAG, $this->post_id);
  1259.                                         }elseif ( preg_match('/^no_tag_([a-zA-Z0-9_\-]+)$/', $condition, $tag_match)){
  1260.                                            //event doesn't have this tag
  1261.                                             $show_condition = !has_term($tag_match[1], EM_TAXONOMY_TAG, $this->post_id);
  1262.                                         }
  1263.                                         //other potential ones - has_attribute_... no_attribute_... has_categories_...
  1264.                                         $show_condition = apply_filters('em_event_output_show_condition', $show_condition, $condition, $conditionals[0][$key], $this);
  1265.                                         if($show_condition){
  1266.                                                 //calculate lengths to delete placeholders
  1267.                                                 $placeholder_length = strlen($condition)+2;
  1268.                                                 $replacement = substr($conditionals[0][$key], $placeholder_length, strlen($conditionals[0][$key])-($placeholder_length *2 +1));
  1269.                                         }else{
  1270.                                                 $replacement = '';
  1271.                                         }
  1272.                                         $event_string = str_replace($conditionals[0][$key], apply_filters('em_event_output_condition', $replacement, $condition, $conditionals[0][$key], $this), $event_string);
  1273.                                 }
  1274.                         }
  1275.                 }
  1276.                 //Now let's check out the placeholders.
  1277.                 preg_match_all("/(#@?_?[A-Za-z0-9]+)({([a-zA-Z0-9_,]+)})?/", $format, $placeholders);
  1278.                 $replaces = array();
  1279.                 foreach($placeholders[1] as $key => $result) {
  1280.                         $match = true;
  1281.                         $replace = '';
  1282.                         $full_result = $placeholders[0][$key];
  1283.                         switch( $result ){
  1284.                                 //Event Details
  1285.                                 case '#_EVENTID':
  1286.                                         $replace = $this->event_id;
  1287.                                         break;
  1288.                                 case '#_EVENTPOSTID':
  1289.                                         $replace = $this->post_id;
  1290.                                         break;
  1291.                                 case '#_NAME': //depreciated
  1292.                                 case '#_EVENTNAME':
  1293.                                         $replace = $this->event_name;
  1294.                                         break;
  1295.                                 case '#_NOTES': //depreciated
  1296.                                 case '#_EXCERPT': //depreciated
  1297.                                 case '#_EVENTNOTES':
  1298.                                 case '#_EVENTEXCERPT':
  1299.                                         $replace = $this->post_content;
  1300.                                         if($result == "#_EXCERPT" || $result == "#_EVENTEXCERPT"){
  1301.                                                 if( !empty($this->post_excerpt) ){
  1302.                                                         $replace = $this->post_excerpt;
  1303.                                                 }else{
  1304.                                                         $matches = explode('<!--more', $this->post_content);
  1305.                                                         $replace = $matches[0];
  1306.                                                 }
  1307.                                         }
  1308.                                         break;
  1309.                                 case '#_EVENTIMAGEURL':
  1310.                                 case '#_EVENTIMAGE':
  1311.                                 if($this->get_image_url() != ''){
  1312.                                                 if($result == '#_EVENTIMAGEURL'){
  1313.                                                 $replace =  esc_url($this->image_url);
  1314.                                                 }else{
  1315.                                                         if( empty($placeholders[3][$key]) ){
  1316.                                                                 $replace = "<img src='".esc_url($this->image_url)."' alt='".esc_attr($this->event_name)."'/>";
  1317.                                                         }else{
  1318.                                                                 $image_size = explode(',', $placeholders[3][$key]);
  1319.                                                                 $image_src = $this->image_url;
  1320.                                                                 if( $this->array_is_numeric($image_size) && count($image_size) > 1 ){
  1321.                                                                     //get a thumbnail
  1322.                                                                     if( get_option('dbem_disable_timthumb') ){
  1323.                                                                             if( EM_MS_GLOBAL && get_current_blog_id() != $this->blog_id ){
  1324.                                                                                 switch_to_blog($this->blog_id);
  1325.                                                                                 $switch_back = true;
  1326.                                                                             }
  1327.                                                                                 $replace = get_the_post_thumbnail($this->ID, $image_size);
  1328.                                                                                 if( !empty($switch_back) ){ restore_current_blog(); }
  1329.                                                                     }else{
  1330.                                                                                 if ( is_multisite() ) { //get the direct url as timthumb doesn't support redirect urls
  1331.                                                                                         global $blog_id;
  1332.                                                                                         $imageParts = explode('/blogs.dir/', $image_src);
  1333.                                                                                         if (isset($imageParts[1])) {
  1334.                                                                                                 $image_src = network_site_url('/wp-content/blogs.dir/'. $imageParts[1]);
  1335.                                                                                         }
  1336.                                                                                 }
  1337.                                                                                 $width = ($image_size[0]) ? 'width="'.esc_attr($image_size[0]).'"':'';
  1338.                                                                                 $height = ($image_size[1]) ? 'height="'.esc_attr($image_size[1]).'"':'';
  1339.                                                                             $replace = "<img src='".esc_url(em_get_thumbnail_url($image_src, $image_size[0], $image_size[1]))."' alt='".esc_attr($this->event_name)."' $width $height />";
  1340.                                                                     }
  1341.                                                                 }else{
  1342.                                                                         $replace = "<img src='".esc_url($image_src)."' alt='".esc_attr($this->event_name)."'/>";
  1343.                                                                 }
  1344.                                                         }
  1345.                                                 }
  1346.                                 }
  1347.                                         break;
  1348.                                 //Times & Dates
  1349.                                 case '#_24HSTARTTIME':
  1350.                                 case '#_24HENDTIME':
  1351.                                         $time = ($result == '#_24HSTARTTIME') ? $this->event_start_time:$this->event_end_time;
  1352.                                         $replace = substr($time, 0,5);
  1353.                                         break;
  1354.                                 case '#_12HSTARTTIME':
  1355.                                 case '#_12HENDTIME':
  1356.                                         $time = ($result == '#_12HSTARTTIME') ? $this->event_start_time:$this->event_end_time;
  1357.                                         $replace = date('g:i A', strtotime($time));
  1358.                                         break;
  1359.                                 case '#_EVENTTIMES':
  1360.                                         //get format of time to show
  1361.                                         if( !$this->event_all_day ){
  1362.                                                 $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
  1363.                                                 if($this->event_start_time != $this->event_end_time ){
  1364.                                                         $replace = date_i18n($time_format, $this->start). get_option('dbem_times_separator') . date_i18n($time_format, $this->end);
  1365.                                                 }else{
  1366.                                                         $replace = date_i18n($time_format, $this->start);
  1367.                                                 }
  1368.                                         }else{
  1369.                                                 $replace = get_option('dbem_event_all_day_message');
  1370.                                         }
  1371.                                         break;
  1372.                                 case '#_EVENTDATES':
  1373.                                         //get format of time to show
  1374.                                         $date_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
  1375.                                         if( $this->event_start_date != $this->event_end_date){
  1376.                                                 $replace = date_i18n($date_format, $this->start). get_option('dbem_dates_separator') . date_i18n($date_format, $this->end);
  1377.                                         }else{
  1378.                                                 $replace = date_i18n($date_format, $this->start);
  1379.                                         }
  1380.                                         break;
  1381.                                 //Links
  1382.                                 case '#_EVENTPAGEURL': //Depreciated   
  1383.                                 case '#_LINKEDNAME': //Depreciated
  1384.                                 case '#_EVENTURL': //Just the URL
  1385.                                 case '#_EVENTLINK': //HTML Link
  1386.                                         $event_link = esc_url($this->get_permalink());
  1387.                                         if($result == '#_LINKEDNAME' || $result == '#_EVENTLINK'){
  1388.                                                 $replace = '<a href="'.$event_link.'" title="'.esc_attr($this->event_name).'">'.esc_attr($this->event_name).'</a>';
  1389.                                         }else{
  1390.                                                 $replace = $event_link;
  1391.                                         }
  1392.                                         break;
  1393.                                 case '#_EDITEVENTURL':
  1394.                                 case '#_EDITEVENTLINK':
  1395.                                         if( $this->can_manage('edit_events','edit_others_events') ){
  1396.                                                 $link = esc_url($this->get_edit_url());
  1397.                                                 if( $result == '#_EDITEVENTLINK'){
  1398.                                                         $replace = '<a href="'.$link.'">'.esc_html(sprintf(__('Edit Event','dbem'))).'</a>';
  1399.                                                 }else{
  1400.                                                         $replace = $link;
  1401.                                                 }
  1402.                                         }        
  1403.                                         break;
  1404.                                 //Bookings
  1405.                                 case '#_ADDBOOKINGFORM': //Depreciated
  1406.                                 case '#_REMOVEBOOKINGFORM': //Depreciated
  1407.                                 case '#_BOOKINGFORM':
  1408.                                         if( get_option('dbem_rsvp_enabled')){
  1409.                                                 ob_start();
  1410.                                                 $template = em_locate_template('placeholders/bookingform.php', true, array('EM_Event'=>$this));
  1411.                                                 EM_Bookings::enqueue_js();
  1412.                                                 $replace = ob_get_clean();
  1413.                                         }
  1414.                                         break;
  1415.                                 case '#_BOOKINGBUTTON':
  1416.                                         if( get_option('dbem_rsvp_enabled') && $this->event_rsvp ){
  1417.                                                 ob_start();
  1418.                                                 $template = em_locate_template('placeholders/bookingbutton.php', true, array('EM_Event'=>$this));
  1419.                                                 $replace = ob_get_clean();
  1420.                                         }
  1421.                                         break;
  1422.                                 case '#_EVENTPRICERANGEALL':                               
  1423.                                     $show_all_ticket_prices = true; //continues below
  1424.                                 case '#_EVENTPRICERANGE':
  1425.                                         //get the range of prices
  1426.                                         $min = false;
  1427.                                         $max = 0;
  1428.                                         if( $this->get_bookings()->is_open() || !empty($show_all_ticket_prices) ){
  1429.                                                 foreach( $this->get_tickets()->tickets as $EM_Ticket ){
  1430.                                                         /* @var $EM_Ticket EM_Ticket */
  1431.                                                         if( $EM_Ticket->is_available() || get_option('dbem_bookings_tickets_show_unavailable') || !empty($show_all_ticket_prices) ){
  1432.                                                                 if($EM_Ticket->get_price() > $max ){
  1433.                                                                         $max = $EM_Ticket->get_price();
  1434.                                                                 }
  1435.                                                                 if($EM_Ticket->get_price() < $min || $min === false){
  1436.                                                                         $min = $EM_Ticket->get_price();
  1437.                                                                 }                                              
  1438.                                                         }
  1439.                                                 }
  1440.                                         }
  1441.                                         if( $min === false ) $min = 0;
  1442.                                         if( $min != $max ){
  1443.                                                 $replace = em_get_currency_formatted($min).' - '.em_get_currency_formatted($max);
  1444.                                         }else{
  1445.                                                 $replace = em_get_currency_formatted($min);
  1446.                                         }
  1447.                                         break;
  1448.                                 case '#_EVENTPRICEMIN':
  1449.                                         //get the range of prices
  1450.                                         $min = false;
  1451.                                         foreach( $this->get_tickets()->tickets as $EM_Ticket ){
  1452.                                                 /* @var $EM_Ticket EM_Ticket */
  1453.                                                 if( $EM_Ticket->is_available()|| get_option('dbem_bookings_tickets_show_unavailable') ){
  1454.                                                         if( $EM_Ticket->get_price() < $min || $min === false){
  1455.                                                                 $min = $EM_Ticket->get_price();
  1456.                                                         }
  1457.                                                 }
  1458.                                         }
  1459.                                         if( $min === false ) $min = 0;
  1460.                                         $replace = em_get_currency_formatted($min);
  1461.                                         break;
  1462.                                 case '#_EVENTPRICEMAX':
  1463.                                         //get the range of prices
  1464.                                         $max = 0;
  1465.                                         foreach( $this->get_tickets()->tickets as $EM_Ticket ){
  1466.                                                 /* @var $EM_Ticket EM_Ticket */
  1467.                                                 if( $EM_Ticket->is_available()|| get_option('dbem_bookings_tickets_show_unavailable') ){
  1468.                                                         if( $EM_Ticket->get_price() > $max ){
  1469.                                                                 $max = $EM_Ticket->get_price();
  1470.                                                         }
  1471.                                                 }                      
  1472.                                         }
  1473.                                         $replace = em_get_currency_formatted($max);
  1474.                                         break;
  1475.                                 case '#_AVAILABLESEATS': //Depreciated
  1476.                                 case '#_AVAILABLESPACES':
  1477.                                         if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
  1478.                                            $replace = $this->get_bookings()->get_available_spaces();
  1479.                                         } else {
  1480.                                                 $replace = "0";
  1481.                                         }
  1482.                                         break;
  1483.                                 case '#_BOOKEDSEATS': //Depreciated
  1484.                                 case '#_BOOKEDSPACES':
  1485.                                         //This placeholder is actually a little misleading, as it'll consider reserved (i.e. pending) bookings as 'booked'
  1486.                                         if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
  1487.                                                 $replace = $this->get_bookings()->get_booked_spaces();
  1488.                                                 if( get_option('dbem_bookings_approval_reserved') ){
  1489.                                                         $replace += $this->get_bookings()->get_pending_spaces();
  1490.                                                 }
  1491.                                         } else {
  1492.                                                 $replace = "0";
  1493.                                         }
  1494.                                         break;
  1495.                                 case '#_PENDINGSPACES':
  1496.                                         if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
  1497.                                            $replace = $this->get_bookings()->get_pending_spaces();
  1498.                                         } else {
  1499.                                                 $replace = "0";
  1500.                                         }
  1501.                                         break;
  1502.                                 case '#_SEATS': //Depreciated
  1503.                                 case '#_SPACES':
  1504.                                         $replace = $this->get_spaces();
  1505.                                         break;
  1506.                                 case '#_BOOKINGSURL':
  1507.                                 case '#_BOOKINGSLINK':
  1508.                                         if( $this->can_manage('manage_bookings','manage_others_bookings') ){
  1509.                                                 $bookings_link = esc_url($this->get_bookings_url());
  1510.                                                 if($result == '#_BOOKINGSLINK'){
  1511.                                                         $replace = '<a href="'.$bookings_link.'" title="'.esc_attr($this->event_name).'">'.esc_html($this->event_name).'</a>';
  1512.                                                 }else{
  1513.                                                         $replace = $bookings_link;     
  1514.                                                 }
  1515.                                         }
  1516.                                         break;
  1517.                                 //Contact Person
  1518.                                 case '#_CONTACTNAME':
  1519.                                 case '#_CONTACTPERSON': //Depreciated (your call, I think name is better)
  1520.                                         $replace = $this->get_contact()->display_name;
  1521.                                         break;
  1522.                                 case '#_CONTACTUSERNAME':
  1523.                                         $replace = $this->get_contact()->user_login;
  1524.                                         break;
  1525.                                 case '#_CONTACTEMAIL':
  1526.                                 case '#_CONTACTMAIL': //Depreciated
  1527.                                         $replace = $this->get_contact()->user_email;
  1528.                                         break;
  1529.                                 case '#_CONTACTURL':
  1530.                                         $replace = $this->get_contact()->user_url;
  1531.                                         break;
  1532.                                 case '#_CONTACTID':
  1533.                                         $replace = $this->get_contact()->ID;
  1534.                                         break;
  1535.                                 case '#_CONTACTPHONE':
  1536.                                 $replace = ( $this->get_contact()->phone != '') ? $this->get_contact()->phone : __('N/A', 'dbem');
  1537.                                         break;
  1538.                                 case '#_CONTACTAVATAR':
  1539.                                         $replace = get_avatar( $this->get_contact()->ID, $size = '50' );
  1540.                                         break;
  1541.                                 case '#_CONTACTPROFILELINK':
  1542.                                 case '#_CONTACTPROFILEURL':
  1543.                                         if( function_exists('bp_core_get_user_domain') ){
  1544.                                                 $replace = bp_core_get_user_domain($this->get_contact()->ID);
  1545.                                                 if( $result == '#_CONTACTPROFILELINK' ){
  1546.                                                         $replace = '<a href="'.esc_url($replace).'">'.__('Profile', 'dbem').'</a>';
  1547.                                                 }
  1548.                                         }
  1549.                                         break;
  1550.                                 case '#_CONTACTMETA':
  1551.                                         if( !empty($placeholders[3][$key]) ){
  1552.                                                 $replace = get_user_meta($this->event_owner, $placeholders[3][$key], true);
  1553.                                         }
  1554.                                         break;
  1555.                                 case '#_ATTENDEES':
  1556.                                         ob_start();
  1557.                                         $template = em_locate_template('placeholders/attendees.php', true, array('EM_Event'=>$this));
  1558.                                         $replace = ob_get_clean();
  1559.                                         break;
  1560.                                 case '#_ATTENDEESLIST':
  1561.                                         ob_start();
  1562.                                         $template = em_locate_template('placeholders/attendeeslist.php', true, array('EM_Event'=>$this));
  1563.                                         $replace = ob_get_clean();
  1564.                                         break;
  1565.                                 case '#_ATTENDEESPENDINGLIST':
  1566.                                         ob_start();
  1567.                                         $template = em_locate_template('placeholders/attendeespendinglist.php', true, array('EM_Event'=>$this));
  1568.                                         $replace = ob_get_clean();
  1569.                                         break;
  1570.                                 //Categories and Tags
  1571.                                 case '#_EVENTCATEGORIESIMAGES':
  1572.                                         ob_start();
  1573.                                         $template = em_locate_template('placeholders/eventcategoriesimages.php', true, array('EM_Event'=>$this));
  1574.                                         $replace = ob_get_clean();
  1575.                                         break;
  1576.                                 case '#_EVENTTAGS':
  1577.                                         ob_start();
  1578.                                         $template = em_locate_template('placeholders/eventtags.php', true, array('EM_Event'=>$this));
  1579.                                         $replace = ob_get_clean();
  1580.                                         break;
  1581.                                 case '#_CATEGORIES': //depreciated
  1582.                                 case '#_EVENTCATEGORIES':
  1583.                                         ob_start();
  1584.                                         $template = em_locate_template('placeholders/categories.php', true, array('EM_Event'=>$this));
  1585.                                         $replace = ob_get_clean();
  1586.                                         break;
  1587.                                 //Ical Stuff
  1588.                                 case '#_EVENTICALURL':
  1589.                                 case '#_EVENTICALLINK':
  1590.                                         $replace = $this->get_ical_url();
  1591.                                         if( $result == '#_EVENTICALLINK' ){
  1592.                                                 $replace = '<a href="'.esc_url($replace).'">iCal</a>';
  1593.                                         }
  1594.                                         break;
  1595.                                 case '#_EVENTGCALURL':
  1596.                                 case '#_EVENTGCALLINK':
  1597.                                         //get dates
  1598.                                         if($this->event_all_day && $this->event_start_date == $this->event_end_date){
  1599.                                                 $dateStart      = date('Ymd',$this->start - (60*60*get_option('gmt_offset')));
  1600.                                                 $dateEnd        = date('Ymd',$this->start + 60*60*24 - (60*60*get_option('gmt_offset')));
  1601.                                         }else{
  1602.                                                 $dateStart      = date('Ymd\THis\Z',$this->start - (60*60*get_option('gmt_offset')));
  1603.                                                 $dateEnd = date('Ymd\THis\Z',$this->end - (60*60*get_option('gmt_offset')));
  1604.                                         }
  1605.                                         //build url
  1606.                                         $gcal_url = 'http://www.google.com/calendar/event?action=TEMPLATE&text=event_name&dates=start_date/end_date&details=post_content&location=location_name&trp=false&sprop=event_url&sprop=name:blog_name';
  1607.                                         $gcal_url = str_replace('event_name', urlencode($this->event_name), $gcal_url);
  1608.                                         $gcal_url = str_replace('start_date', urlencode($dateStart), $gcal_url);
  1609.                                         $gcal_url = str_replace('end_date', urlencode($dateEnd), $gcal_url);
  1610.                                         $gcal_url = str_replace('location_name', urlencode($this->output('#_LOCATION')), $gcal_url);
  1611.                                         $gcal_url = str_replace('blog_name', urlencode(get_bloginfo()), $gcal_url);
  1612.                                         $gcal_url = str_replace('event_url', urlencode($this->get_permalink()), $gcal_url);
  1613.                                         //calculate URL length so we know how much we can work with to make a description.
  1614.                                         if( !empty($this->post_excerpt) ){
  1615.                                                 $gcal_url_description = $this->post_excerpt;
  1616.                                         }else{
  1617.                                                 $matches = explode('<!--more', $this->post_content);
  1618.                                                 $gcal_url_description = wp_kses_data($matches[0]);
  1619.                                         }
  1620.                                         $gcal_url_length = strlen($gcal_url) - 9;
  1621.                                         if( strlen($gcal_url_description) + $gcal_url_length > 1350 ){
  1622.                                                 $gcal_url_description = substr($gcal_url_description, 0, 1380 - $gcal_url_length - 3 ).'...';
  1623.                                         }
  1624.                                         $gcal_url = str_replace('post_content', urlencode($gcal_url_description), $gcal_url);
  1625.                                         //get the final url
  1626.                                         $replace = $gcal_url;
  1627.                                         if( $result == '#_EVENTGCALLINK' ){
  1628.                                                 $img_url = 'www.google.com/calendar/images/ext/gc_button2.gif';
  1629.                                                 $img_url = is_ssl() ? 'https://'.$img_url:'http://'.$img_url;
  1630.                                                 $replace = '<a href="'.esc_url($replace).'" target="_blank"><img src="'.esc_url($img_url).'" alt="0" border="0"></a>';
  1631.                                         }
  1632.                                         break;
  1633.                                 default:
  1634.                                         $replace = $full_result;
  1635.                                         break;
  1636.                         }
  1637.                         $replaces[$full_result] = apply_filters('em_event_output_placeholder', $replace, $this, $full_result, $target);
  1638.                 }
  1639.                 //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
  1640.                 krsort($replaces);
  1641.                 foreach($replaces as $full_result => $replacement){
  1642.                         if( !in_array($full_result, array('#_NOTES','#_EVENTNOTES')) ){
  1643.                                 $event_string = str_replace($full_result, $replacement , $event_string );
  1644.                         }else{
  1645.                             $new_placeholder = str_replace('#_', '__#', $full_result); //this will avoid repeated filters when locations/categories are parsed
  1646.                             $event_string = str_replace($full_result, $new_placeholder , $event_string );
  1647.                                 $desc_replace[$new_placeholder] = $replacement;
  1648.                         }
  1649.                 }
  1650.                 //Time placeholders
  1651.                 foreach($placeholders[1] as $result) {
  1652.                         // matches all PHP START date and time placeholders
  1653.                         if (preg_match('/^#[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
  1654.                                 $replace = date_i18n(ltrim($result, "#"), $this->start);
  1655.                                 $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target);
  1656.                                 $event_string = str_replace($result, $replace, $event_string );
  1657.                         }
  1658.                         // matches all PHP END time placeholders for endtime
  1659.                         if (preg_match('/^#@[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
  1660.                                 $replace = date_i18n(ltrim($result, "#@"), $this->end);
  1661.                                 $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target);
  1662.                                 $event_string = str_replace($result, $replace, $event_string );
  1663.                         }
  1664.                 }
  1665.                 //Now do dependent objects
  1666.                 if( !empty($this->location_id) && $this->get_location()->location_status ){
  1667.                         $event_string = $this->get_location()->output($event_string, $target);
  1668.                 }else{
  1669.                         $EM_Location = new EM_Location();
  1670.                         $event_string = $EM_Location->output($event_string, $target);
  1671.                 }
  1672.                
  1673.                 //for backwards compat and easy use, take over the individual category placeholders with the frirst cat in th elist.
  1674.                 $EM_Categories = $this->get_categories();
  1675.                 if( count($EM_Categories->categories) > 0 ){
  1676.                         $EM_Category = $EM_Categories->get_first();
  1677.                 }      
  1678.                
  1679.                 if( empty($EM_Category) ) $EM_Category = new EM_Category();
  1680.                 $event_string = $EM_Category->output($event_string, $target);
  1681.                
  1682.                 //Finally, do the event notes, so that previous placeholders don't get replaced within the content, which may use shortcodes
  1683.                 if( !empty($desc_replace) ){
  1684.                         foreach($desc_replace as $full_result => $replacement){
  1685.                                 $event_string = str_replace($full_result, $replacement , $event_string );
  1686.                         }
  1687.                 }
  1688.                
  1689.                 return apply_filters('em_event_output', $event_string, $this, $format, $target);
  1690.         }      
  1691.        
  1692.         /**********************************************************
  1693.          * RECURRENCE METHODS
  1694.          ***********************************************************/
  1695.        
  1696.         /**
  1697.          * Returns true if this is a recurring event.
  1698.          * @return boolean
  1699.          */
  1700.         function is_recurring(){
  1701.                 return $this->post_type == 'event-recurring' && get_option('dbem_recurrence_enabled');
  1702.         }      
  1703.         /**
  1704.          * Will return true if this individual event is part of a set of events that recur
  1705.          * @return boolean
  1706.          */
  1707.         function is_recurrence(){
  1708.                 return ( $this->event_id > 0 && $this->recurrence_id > 0 && get_option('dbem_recurrence_enabled') );
  1709.         }
  1710.         /**
  1711.          * Returns if this is an individual event and is not a recurrence
  1712.          * @return boolean
  1713.          */
  1714.         function is_individual(){
  1715.                 return ( !$this->is_recurring() && !$this->is_recurrence() );
  1716.         }
  1717.        
  1718.         /**
  1719.          * Gets the event recurrence template, which is an EM_Event_Recurrence object (based off an event-recurring post)
  1720.          * @return EM_Event_Recurrence
  1721.          */
  1722.         function get_event_recurrence(){
  1723.                 if(!$this->is_recurring()){
  1724.                         return new EM_Event($this->recurrence_id); //remember, recurrence_id is a post!
  1725.                 }else{
  1726.                         return $this;
  1727.                 }
  1728.         }
  1729.        
  1730.         function get_detach_url(){
  1731.                 return admin_url().'admin.php?event_id='.$this->event_id.'&amp;action=event_detach&amp;_wpnonce='.wp_create_nonce('event_detach_'.get_current_user_id().'_'.$this->event_id);
  1732.         }
  1733.        
  1734.         function get_attach_url($recurrence_id){
  1735.                 return admin_url().'admin.php?undo_id='.$recurrence_id.'&amp;event_id='.$this->event_id.'&amp;action=event_attach&amp;_wpnonce='.wp_create_nonce('event_attach_'.get_current_user_id().'_'.$this->event_id);
  1736.         }
  1737.        
  1738.         /**
  1739.          * Returns if this is an individual event and is not recurring or a recurrence
  1740.          * @return boolean
  1741.          */
  1742.         function detach(){
  1743.                 global $wpdb;
  1744.                 if( $this->is_recurrence() && !$this->is_recurring() && $this->can_manage('edit_recurring_events','edit_others_recurring_events') ){
  1745.                         //remove recurrence id from post meta and index table
  1746.                         $url = $this->get_attach_url($this->recurrence_id);
  1747.                         $wpdb->update(EM_EVENTS_TABLE, array('recurrence_id'=>0), array('event_id' => $this->event_id));
  1748.                         update_post_meta($this->post_id, '_recurrence_id', 0);
  1749.                         $this->feedback_message = __('Event detached.','dbem') . ' <a href="'.$url.'">'.__('Undo','dbem').'</a>';
  1750.                         $this->recurrence_id = 0;
  1751.                         return true;
  1752.                 }
  1753.                 $this->add_error(__('Event could not be detached.','dbem'));
  1754.                 return false;
  1755.         }
  1756.        
  1757.         /**
  1758.          * Returns if this is an individual event and is not recurring or a recurrence
  1759.          * @return boolean
  1760.          */
  1761.         function attach($recurrence_id){
  1762.                 global $wpdb;
  1763.                 if( !$this->is_recurrence() && !$this->is_recurring() && is_numeric($recurrence_id) && $this->can_manage('edit_recurring_events','edit_others_recurring_events') ){
  1764.                         //add recurrence id to post meta and index table
  1765.                         $wpdb->update(EM_EVENTS_TABLE, array('recurrence_id'=>$recurrence_id), array('event_id' => $this->event_id));
  1766.                         update_post_meta($this->post_id, '_recurrence_id', $recurrence_id);
  1767.                         $this->feedback_message = __('Event re-attached to recurrence.','dbem');
  1768.                         return true;
  1769.                 }
  1770.                 $this->add_error(__('Event could not be attached.','dbem'));
  1771.                 return false;
  1772.         }
  1773.        
  1774.         /**
  1775.          * Saves events and replaces old ones. Returns true if sucecssful or false if not.
  1776.          * @return boolean
  1777.          */
  1778.         function save_events() {
  1779.                 global $wpdb;
  1780.                 if( $this->can_manage('edit_events','edit_others_events') && $this->is_published() ){
  1781.                         do_action('em_event_save_events_pre', $this); //actions/filters only run if event is recurring
  1782.                         //Make template event index, post, and meta (and we just change event dates)
  1783.                         $event = $this->to_array(true); //event template - for index
  1784.                         $event['event_attributes'] = serialize($event['event_attributes']);
  1785.                         $post_fields = $wpdb->get_row('SELECT * FROM '.$wpdb->posts.' WHERE ID='.$this->post_id, ARRAY_A); //post to copy
  1786.                         $post_name = $post_fields['post_name']; //save post slug since we'll be using this
  1787.                         $post_fields['post_type'] = 'event'; //make sure we'll save events, not recurrence templates
  1788.                         $meta_fields_map = $wpdb->get_results('SELECT meta_key,meta_value FROM '.$wpdb->postmeta.' WHERE post_id='.$this->post_id, ARRAY_A);
  1789.                         $meta_fields = array();
  1790.                         //convert meta_fields into a cleaner array
  1791.                         foreach($meta_fields_map as $meta_data){
  1792.                                 $meta_fields[$meta_data['meta_key']] = $meta_data['meta_value'];
  1793.                         }
  1794.                         //remove id and we have a event template to feed to wpdb insert
  1795.                         unset($event['event_id']);
  1796.                         unset($post_fields['ID']);
  1797.                         //remove recurrence meta info we won't need in events
  1798.                         foreach( array_keys($this->recurrence_fields) as $recurrence_field){
  1799.                                 unset($event[$recurrence_field]);
  1800.                                 unset($meta_fields['_'.$recurrence_field]);
  1801.                         }              
  1802.                         $event['event_date_created'] = current_time('mysql'); //since the recurrences are recreated
  1803.                         unset($event['event_date_modified']);
  1804.                         //Set the recurrence ID
  1805.                         $event['recurrence_id'] = $meta_fields['_recurrence_id'] = $this->event_id;
  1806.                         $event['recurrence'] = $meta_fields['_recurrence'] = 0;
  1807.                         //Let's start saving!
  1808.                         $this->delete_events(); //Delete old events beforehand, this will change soon
  1809.                         $event_saves = array();
  1810.                         $event_ids = array();
  1811.                         $event_start = array();
  1812.                         $post_ids = array();
  1813.                         $matching_days = $this->get_recurrence_days(); //Get days where events recur
  1814.                         if( count($matching_days) > 0 ){
  1815.                                 //first save event post data
  1816.                                 $recurring_date_format = apply_filters('em_event_save_events_format', 'Y-m-d');
  1817.                                 foreach( $matching_days as $day ) {
  1818.                                         //rewrite post fields if needed
  1819.                                         $post_fields['post_name'] = $event['event_slug'] = $meta_fields['_event_slug'] = apply_filters('em_event_save_events_slug', $post_name.'-'.date($recurring_date_format, $day), $post_fields, $day, $matching_days, $this);
  1820.                                         //adjust certain meta information
  1821.                                         $event['event_start_date'] = $meta_fields['_event_start_date'] = date("Y-m-d", $day);
  1822.                                         $meta_fields['_start_ts'] = strtotime($event['event_start_date'].' '.$event['event_start_time']);
  1823.                                         $event['event_rsvp_date'] = $meta_fields['_event_rsvp_date'] = $event['event_start_date'];
  1824.                                         $event['event_rsvp_time'] = $meta_fields['_event_rsvp_time'] = $event['event_start_time'];
  1825.                                         if($this->recurrence_days > 0){
  1826.                                                 $event['event_end_date'] = $meta_fields['_event_end_date'] = date("Y-m-d", $meta_fields['_start_ts'] + ($this->recurrence_days * 60*60*24));
  1827.                                         }else{
  1828.                                                 $event['event_end_date'] = $meta_fields['_event_end_date'] = $event['event_start_date'];
  1829.                                         }      
  1830.                                         $meta_fields['_end_ts'] = strtotime($event['event_end_date'].' '.$event['event_end_time']);
  1831.                                         //create the event
  1832.                                         if( $wpdb->insert($wpdb->posts, $post_fields ) ){
  1833.                                                 $event['post_id'] = $meta_fields['_post_id'] = $post_id = $post_ids[] = $wpdb->insert_id; //post id saved into event and also as a var for later user
  1834.                                                 // Set GUID and event slug as per wp_insert_post
  1835.                                                 $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_id ) ), array('ID'=>$post_id) );
  1836.                                                 //insert into events index table
  1837.                                                 $event_saves[] = $wpdb->insert(EM_EVENTS_TABLE, $event);
  1838.                                                 $event_ids[] = $event_id = $wpdb->insert_id;
  1839.                                                 //create the meta inserts for each event
  1840.                                                 $meta_fields['_event_id'] = $event_id;
  1841.                                                 foreach($meta_fields as $meta_key => $meta_val){
  1842.                                                         $meta_inserts[] = $wpdb->prepare("(%d, '%s', '%s')", array($post_id, $meta_key, $meta_val));
  1843.                                                 }
  1844.                                                 $event_start[$event_id] = $day;
  1845.                                         }else{
  1846.                                                 $event_saves[] = false;
  1847.                                         }
  1848.                                         //if( EM_DEBUG ){ echo "Entering recurrence " . date("D d M Y", $day)."<br/>"; }
  1849.                                 }
  1850.                                 //insert the metas in one go, faster than one by one
  1851.                                 if( count($meta_inserts) > 0 ){
  1852.                                         $result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
  1853.                                         if($result === false){
  1854.                                                 $this->add_error('There was a problem adding custom fields to your recurring events.','dbem');
  1855.                                         }
  1856.                                 }
  1857.                                 //copy the event tags and categories
  1858.                                 $categories = $this->get_categories()->categories;
  1859.                                 foreach( $categories as $category){
  1860.                                         if( !empty($category->slug) ) $cat_slugs[] = $category->slug; //save of category will soft-fail if slug is empty
  1861.                                 }
  1862.                                 $cat_slugs_count = count($categories);
  1863.                                 $tags = get_the_terms( $this->post_id, EM_TAXONOMY_TAG);
  1864.                                 $tax_slugs = array();
  1865.                                 if( is_array($tags) ){
  1866.                                         foreach($tags as $tag){
  1867.                                                 if( !empty($tag->slug) ) $tax_slugs[] = $tag->slug; //save of category will soft-fail if slug is empty
  1868.                                         }
  1869.                                 }
  1870.                                 $tax_slugs_count = count($tags);
  1871.                                 foreach($post_ids as $post_id){
  1872.                                         if( $cat_slugs_count > 0 && !EM_MS_GLOBAL ){
  1873.                                                 wp_set_object_terms($post_id, $cat_slugs, EM_TAXONOMY_CATEGORY);
  1874.                                         }
  1875.                                         if( $tax_slugs_count > 0 ){
  1876.                                                 wp_set_object_terms($post_id, $tax_slugs, EM_TAXONOMY_TAG);
  1877.                                         }
  1878.                                 }
  1879.                                 //featured images
  1880.                                 if( !empty($this->attributes['thumbnail_id']) ){
  1881.                                         $image_inserts = array();
  1882.                                         foreach($post_ids as $post_ids){
  1883.                                                 $image_inserts[] = "({$this->post_id}, '_thumbnail_id', {$this->attributes['thumbnail_id']})";
  1884.                                         }
  1885.                                         if( count($image_inserts) > 0 ){
  1886.                                                 $wpdb->query('INSERT INTO '.$wpdb->postmeta.' (post_id, meta_key, meta_value) VALUES '.implode(', ', $image_inserts));
  1887.                                         }
  1888.                                 }
  1889.                                 //MS Global Categories
  1890.                                 if( $cat_slugs_count > 0 && EM_MS_GLOBAL ){
  1891.                                         foreach($categories as $EM_Category){
  1892.                                                 foreach($event_ids as $event_id){
  1893.                                                         $wpdb->insert(EM_META_TABLE, array('meta_value'=>$EM_Category->term_id,'object_id'=>$event_id,'meta_key'=>'event-category'));
  1894.                                                 }
  1895.                                         }
  1896.                                 }
  1897.                                 //now, save booking info for each event
  1898.                                 if( $this->event_rsvp ){
  1899.                                         $meta_inserts = array();
  1900.                                         $base_event_start_ts = strtotime( $this->event_start_date );
  1901.                                        
  1902.                                         foreach($this->get_tickets() as $EM_Ticket){
  1903.                                                 /* @var $EM_Ticket EM_Ticket */
  1904.                                                 //get array, modify event id and insert
  1905.                                                 $ticket = $EM_Ticket->to_array();
  1906.                                                 unset($ticket['ticket_id']);
  1907.                                                 //clean up ticket values
  1908.                                                 foreach($ticket as $k => $v){
  1909.                                                         if( empty($v) && $k != 'ticket_name' ){
  1910.                                                                 $ticket[$k] = 'NULL';
  1911.                                                         }else{
  1912.                                                                 $data_type = !empty($EM_Ticket->fields[$k]['type']) ? $EM_Ticket->fields[$k]['type']:'%s';
  1913.                                                                 $ticket[$k] = $wpdb->prepare($data_type,$v);
  1914.                                                         }
  1915.                                                 }
  1916.                                                
  1917.                                                 $base_ticket_start_ts = strtotime( str_replace( "'", '', $ticket['ticket_start'] ) );
  1918.                                                 $base_ticket_end_ts = strtotime( str_replace( "'", '', $ticket['ticket_end'] ) );
  1919.                                                
  1920.                                                 foreach($event_ids as $event_id){
  1921.                                                         if( $base_ticket_start_ts )
  1922.                                                                 $ticket['ticket_start'] = "'" . date("Y-m-d", $base_ticket_start_ts + ( $event_start[ $event_id ] - $base_event_start_ts ) ) . "'";
  1923.  
  1924.                                                         if( $base_ticket_end_ts )
  1925.                                                                 $ticket['ticket_end'] = "'" . date("Y-m-d", $base_ticket_end_ts + ( $event_start[ $event_id ] - $base_event_start_ts ) ) . "'";
  1926.                                                
  1927.                                                         $ticket['event_id'] = $event_id;
  1928.                                                         $meta_inserts[] = "(".implode(",",$ticket).")";
  1929.                                                 }
  1930.                                         }
  1931.                                         $keys = "(".implode(",",array_keys($ticket)).")";
  1932.                                         $values = implode(',',$meta_inserts);
  1933.                                         $sql = "INSERT INTO ".EM_TICKETS_TABLE." $keys VALUES $values";
  1934.                                         $result = $wpdb->query($sql);
  1935.                                 }
  1936.                         }else{
  1937.                                 $this->add_error('You have not defined a date range long enough to create a recurrence.','dbem');
  1938.                                 $result = false;
  1939.                         }
  1940.                         return apply_filters('em_event_save_events', !in_array(false, $event_saves) && $result !== false, $this, $event_ids, $post_ids);
  1941.                 }
  1942.                 return apply_filters('em_event_save_events', false, $this, $event_ids, $post_ids);
  1943.         }
  1944.        
  1945.         /**
  1946.          * Removes all reoccurring events.
  1947.          * @param $recurrence_id
  1948.          * @return null
  1949.          */
  1950.         function delete_events(){
  1951.                 global $wpdb;
  1952.                 do_action('em_event_delete_events_pre', $this);
  1953.                 //So we don't do something we'll regret later, we could just supply the get directly into the delete, but this is safer
  1954.                 $result = false;
  1955.                 if( $this->can_manage('delete_events', 'delete_others_events') ){
  1956.                         //delete events from em_events table
  1957.                         $events_array = EM_Events::get( array('recurrence_id'=>$this->event_id, 'scope'=>'all', 'status'=>false ) );
  1958.                         foreach($events_array as $EM_Event){
  1959.                                 /* @var $EM_Event EM_Event */
  1960.                                 if($EM_Event->recurrence_id == $this->event_id){
  1961.                                         $EM_Event->delete(true);
  1962.                                 }
  1963.                         }                      
  1964.                 }
  1965.                 return apply_filters('delete_events', $result, $this, $events_array);
  1966.         }
  1967.        
  1968.         /**
  1969.          * Returns the days that match the recurrance array passed (unix timestamps)
  1970.          * @param array $recurrence
  1971.          * @return array
  1972.          */
  1973.         function get_recurrence_days(){                
  1974.                 $start_date = strtotime($this->event_start_date);
  1975.                 $end_date = strtotime($this->event_end_date);
  1976.                                
  1977.                 $weekdays = explode(",", $this->recurrence_byday); //what days of the week (or if monthly, one value at index 0)
  1978.                  
  1979.                 $matching_days = array();
  1980.                 $aDay = 86400;  // a day in seconds
  1981.                 $aWeek = $aDay * 7;              
  1982.                        
  1983.                 //TODO can this be optimized?
  1984.                 switch ( $this->recurrence_freq ){
  1985.                         case 'daily':
  1986.                                 //If daily, it's simple. Get start date, add interval timestamps to that and create matching day for each interval until end date.
  1987.                                 $current_date = $start_date;
  1988.                                 while( $current_date <= $end_date ){
  1989.                                         $matching_days[] = $current_date;
  1990.                                         $current_date = $current_date + ($aDay * $this->recurrence_interval);
  1991.                                 }
  1992.                                 break;
  1993.                         case 'weekly':
  1994.                                 //sort out week one, get starting days and then days that match time span of event (i.e. remove past events in week 1)
  1995.                                 $start_of_week = get_option('start_of_week'); //Start of week depends on WordPress
  1996.                                 //first, get the start of this week as timestamp
  1997.                                 $event_start_day = date('w', $start_date);
  1998.                                 //then get the timestamps of weekdays during this first week, regardless if within event range
  1999.                                 $start_weekday_dates = array(); //Days in week 1 where there would events, regardless of event date range
  2000.                                 for($i = 0; $i < 7; $i++){
  2001.                                         $weekday_date = $start_date+($aDay*$i); //the date of the weekday we're currently checking
  2002.                                         $weekday_day = date('w',$weekday_date); //the day of the week we're checking, taking into account wp start of week setting
  2003.  
  2004.                                         if( in_array( $weekday_day, $weekdays) ){
  2005.                                                 $start_weekday_dates[] = $weekday_date; //it's in our starting week day, so add it
  2006.                                         }
  2007.                                 }                                      
  2008.                                 //for each day of eventful days in week 1, add 7 days * weekly intervals
  2009.                                 foreach ($start_weekday_dates as $weekday_date){
  2010.                                         //Loop weeks by interval until we reach or surpass end date
  2011.                                         while($weekday_date <= $end_date){
  2012.                                                 if( $weekday_date >= $start_date && $weekday_date <= $end_date ){
  2013.                                                         $matching_days[] = $weekday_date;
  2014.                                                 }
  2015.                                                 $weekday_date = $weekday_date + ($aWeek *  $this->recurrence_interval);
  2016.                                         }
  2017.                                 }//done!
  2018.                                 break;  
  2019.                         case 'monthly':
  2020.                                 //loop months starting this month by intervals
  2021.                                 $current_arr = getdate($start_date);
  2022.                                 $end_arr = getdate($end_date);
  2023.                                 $end_month_date = strtotime( date('Y-m-t', $end_date) ); //End date on last day of month
  2024.                                 $current_date = strtotime( date('Y-m-1', $start_date) ); //Start date on first day of month
  2025.                                 while( $current_date <= $end_month_date ){
  2026.                                         $last_day_of_month = date('t', $current_date);
  2027.                                         //Now find which day we're talking about
  2028.                                         $current_week_day = date('w',$current_date);
  2029.                                         $matching_month_days = array();
  2030.                                         //Loop through days of this years month and save matching days to temp array
  2031.                                         for($day = 1; $day <= $last_day_of_month; $day++){
  2032.                                                 if((int) $current_week_day == $this->recurrence_byday){
  2033.                                                         $matching_month_days[] = $day;
  2034.                                                 }
  2035.                                                 $current_week_day = ($current_week_day < 6) ? $current_week_day+1 : 0;                                                 
  2036.                                         }
  2037.                                         //Now grab from the array the x day of the month
  2038.                                         $matching_day = ($this->recurrence_byweekno > 0) ? $matching_month_days[$this->recurrence_byweekno-1] : array_pop($matching_month_days);
  2039.                                         $matching_date = strtotime(date('Y-m',$current_date).'-'.$matching_day);
  2040.                                         if($matching_date >= $start_date && $matching_date <= $end_date){
  2041.                                                 $matching_days[] = $matching_date;
  2042.                                         }
  2043.                                         //add the number of days in this month to make start of next month
  2044.                                         $current_arr['mon'] += $this->recurrence_interval;
  2045.                                         if($current_arr['mon'] > 12){
  2046.                                                 //FIXME this won't work if interval is more than 12
  2047.                                                 $current_arr['mon'] = $current_arr['mon'] - 12;
  2048.                                                 $current_arr['year']++;
  2049.                                         }
  2050.                                         $current_date = strtotime("{$current_arr['year']}-{$current_arr['mon']}-1");
  2051.                                 }
  2052.                                 break;
  2053.                         case 'yearly':
  2054.                                 //If yearly, it's simple. Get start date, add interval timestamps to that and create matching day for each interval until end date.
  2055.                                 $month = date('m', $this->start);
  2056.                                 $day = date('d',$this->start);
  2057.                                 $year = date('Y',$this->start);
  2058.                                 $end_year = date('Y',$this->end);
  2059.                                 if( @mktime(0,0,0,$day,$month,$end_year) < $this->end ) $end_year--;
  2060.                                 while( $year <= $end_year ){
  2061.                                         $matching_days[] = mktime(0,0,0,$month,$day,$year);
  2062.                                         $year++;
  2063.                                 }                      
  2064.                                 break;
  2065.                 }
  2066.                 sort($matching_days);
  2067.                 return apply_filters('em_events_get_recurrence_days', $matching_days, $this);
  2068.         }
  2069.        
  2070.         /**
  2071.          * If event is recurring, set recurrences to same status as template
  2072.          * @param $status
  2073.          */
  2074.         function set_status_events($status){
  2075.                 //give sub events same status
  2076.                 $events_array = EM_Events::get( array('recurrence_id'=>$this->post_id, 'scope'=>'all', 'status'=>false ) );
  2077.                 foreach($events_array as $EM_Event){
  2078.                         /* @var $EM_Event EM_Event */
  2079.                         if($EM_Event->recurrence_id == $this->event_id){
  2080.                                 $EM_Event->set_status($status);
  2081.                         }
  2082.                 }
  2083.         }
  2084.        
  2085.         /**
  2086.          * Returns a string representation of this recurrence. Will return false if not a recurrence
  2087.          * @return string
  2088.          */
  2089.         function get_recurrence_description() {
  2090.                 $EM_Event_Recurring = $this->get_event_recurrence();
  2091.                 $recurrence = $this->to_array();
  2092.                 $weekdays_name = array(__('Sunday', 'dbem'),__('Monday', 'dbem'),__('Tuesday', 'dbem'),__('Wednesday', 'dbem'),__('Thursday', 'dbem'),__('Friday', 'dbem'),__('Saturday', 'dbem'));
  2093.                 $monthweek_name = array('1' => __('the first %s of the month', 'dbem'),'2' => __('the second %s of the month', 'dbem'), '3' => __('the third %s of the month', 'dbem'), '4' => __('the fourth %s of the month', 'dbem'), '-1' => __('the last %s of the month', 'dbem'));
  2094.                 $output = sprintf (__('From %1$s to %2$s', 'dbem'),  $EM_Event_Recurring->event_start_date, $EM_Event_Recurring->event_end_date).", ";
  2095.                 if ($EM_Event_Recurring->recurrence_freq == 'daily')  {
  2096.                         $freq_desc =__('everyday', 'dbem');
  2097.                         if ($EM_Event_Recurring->recurrence_interval > 1 ) {
  2098.                                 $freq_desc = sprintf (__("every %s days", 'dbem'), $EM_Event_Recurring->recurrence_interval);
  2099.                         }
  2100.                 }elseif ($EM_Event_Recurring->recurrence_freq == 'weekly')  {
  2101.                         $weekday_array = explode(",", $EM_Event_Recurring->recurrence_byday);
  2102.                         $natural_days = array();
  2103.                         foreach($weekday_array as $day){
  2104.                                 array_push($natural_days, $weekdays_name[$day]);
  2105.                         }
  2106.                         $output .= implode(", ", $natural_days);
  2107.                         $freq_desc = " " . __("every week", 'dbem');
  2108.                         if ($EM_Event_Recurring->recurrence_interval > 1 ) {
  2109.                                 $freq_desc = " ".sprintf (__("every %s weeks", 'dbem'), $EM_Event_Recurring->recurrence_interval);
  2110.                         }
  2111.                        
  2112.                 }elseif ($EM_Event_Recurring->recurrence_freq == 'monthly')  {
  2113.                         $weekday_array = explode(",", $EM_Event_Recurring->recurrence_byday);
  2114.                         $natural_days = array();
  2115.                         foreach($weekday_array as $day){
  2116.                                 array_push($natural_days, $weekdays_name[$day]);
  2117.                         }
  2118.                         $freq_desc = sprintf (($monthweek_name[$EM_Event_Recurring->recurrence_byweekno]), implode(" and ", $natural_days));
  2119.                         if ($EM_Event_Recurring->recurrence_interval > 1 ) {
  2120.                                 $freq_desc .= ", ".sprintf (__("every %s months",'dbem'), $EM_Event_Recurring->recurrence_interval);
  2121.                         }
  2122.                 }elseif ($EM_Event_Recurring->recurrence_freq == 'yearly')  {
  2123.                         $freq_desc .= __("every year", 'dbem');
  2124.                         if ($EM_Event_Recurring->recurrence_interval > 1 ) {
  2125.                                 $freq_desc .= sprintf (__("every %s years",'dbem'), $EM_Event_Recurring->recurrence_interval);
  2126.                         }
  2127.                 }else{
  2128.                         $freq_desc = "[ERROR: corrupted database record]";
  2129.                 }
  2130.                 $output .= $freq_desc;
  2131.                 return  $output;
  2132.         }      
  2133.        
  2134.         /**********************************************************
  2135.          * UTILITIES
  2136.          ***********************************************************/
  2137.        
  2138.         /**
  2139.          * Can the user manage this?
  2140.          */
  2141.         function can_manage( $owner_capability = false, $admin_capability = false, $user_to_check = false ){
  2142.                 if( $this->event_id == '' && !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') ){
  2143.                         $user_to_check = get_option('dbem_events_anonymous_user');
  2144.                 }
  2145.                 return apply_filters('em_event_can_manage', parent::can_manage($owner_capability, $admin_capability, $user_to_check), $this, $owner_capability, $admin_capability, $user_to_check);
  2146.         }
  2147. }
  2148.  
  2149. //TODO placeholder targets filtering could be streamlined better
  2150. /**
  2151.  * This is a temporary filter function which mimicks the old filters in the old 2.x placeholders function
  2152.  * @param string $result
  2153.  * @param EM_Event $event
  2154.  * @param string $placeholder
  2155.  * @param string $target
  2156.  * @return mixed
  2157.  */
  2158. function em_event_output_placeholder($result,$event,$placeholder,$target='html'){
  2159.         if( $target == 'raw' ) return $result;
  2160.         if( in_array($placeholder, array("#_EXCERPT",'#_EVENTEXCERPT', "#_LOCATIONEXCERPT")) && $target == 'html' ){
  2161.                 $result = apply_filters('dbem_notes_excerpt', $result);
  2162.         }elseif( $placeholder == '#_CONTACTEMAIL' && $target == 'html' ){
  2163.                 $result = em_ascii_encode($event->get_contact()->user_email);
  2164.         }elseif( in_array($placeholder, array('#_EVENTNOTES','#_NOTES','#_DESCRIPTION','#_LOCATIONNOTES','#_CATEGORYNOTES','#_CATEGORYDESCRIPTION')) ){
  2165.                 if($target == 'rss'){
  2166.                         $result = apply_filters('dbem_notes_rss', $result);
  2167.                         $result = apply_filters('the_content_rss', $result);
  2168.                 }elseif($target == 'map'){
  2169.                         $result = apply_filters('dbem_notes_map', $result);
  2170.                 }elseif($target == 'ical'){
  2171.                         $result = apply_filters('dbem_notes_ical', $result);
  2172.                 }elseif ($target == "email"){    
  2173.                         $result = apply_filters('dbem_notes_email', $result);
  2174.                 }else{ //html
  2175.                         $result = apply_filters('dbem_notes', $result);
  2176.                 }
  2177.         }elseif( in_array($placeholder, array("#_NAME",'#_LOCATION','#_TOWN','#_ADDRESS','#_LOCATIONNAME',"#_EVENTNAME","#_LOCATIONNAME",'#_CATEGORY')) ){
  2178.                 if ($target == "rss"){
  2179.                         $result = apply_filters('dbem_general_rss', $result);
  2180.                 }elseif ($target == "ical"){    
  2181.                         $result = apply_filters('dbem_general_ical', $result);
  2182.                 }elseif ($target == "email"){    
  2183.                         $result = apply_filters('dbem_general_email', $result);
  2184.                 }else{ //html
  2185.                         $result = apply_filters('dbem_general', $result);
  2186.                 }                              
  2187.         }
  2188.         return $result;
  2189. }
  2190. add_filter('em_category_output_placeholder','em_event_output_placeholder',1,4);
  2191. add_filter('em_event_output_placeholder','em_event_output_placeholder',1,4);
  2192. add_filter('em_location_output_placeholder','em_event_output_placeholder',1,4);
  2193. // FILTERS
  2194. // filters for general events field (corresponding to those of  "the _title")
  2195. add_filter('dbem_general', 'wptexturize');
  2196. add_filter('dbem_general', 'convert_chars');
  2197. add_filter('dbem_general', 'trim');
  2198. // filters for the notes field in html (corresponding to those of  "the _content")
  2199. add_filter('dbem_notes', 'wptexturize');
  2200. add_filter('dbem_notes', 'convert_smilies');
  2201. add_filter('dbem_notes', 'convert_chars');
  2202. add_filter('dbem_notes', 'wpautop');
  2203. add_filter('dbem_notes', 'prepend_attachment');
  2204. add_filter('dbem_notes', 'do_shortcode');
  2205. // RSS content filter
  2206. add_filter('dbem_notes_rss', 'convert_chars', 8);
  2207. add_filter('dbem_general_rss', 'esc_html', 8);
  2208. // Notes map filters
  2209. add_filter('dbem_notes_map', 'convert_chars', 8);
  2210. add_filter('dbem_notes_map', 'js_escape');
  2211. //embeds support if using placeholders
  2212. if ( is_object($GLOBALS['wp_embed']) ){
  2213.         add_filter( 'dbem_notes', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
  2214.         add_filter( 'dbem_notes', array( $GLOBALS['wp_embed'], 'autoembed' ), 8 );
  2215. }
  2216.  
  2217. /**
  2218.  * This function replaces the default gallery shortcode, so it can check if this is a recurring event recurrence and pass on the parent post id as the default post.
  2219.  * @param array $attr
  2220.  */
  2221. function em_event_gallery_override( $attr = array() ){
  2222.         global $post;
  2223.         if( $post->post_type == EM_POST_TYPE_EVENT && empty($attr['id']) && empty($attr['ids']) ){
  2224.                 //no id specified, so check if it's recurring and override id with recurrence template post id
  2225.                 $EM_Event = em_get_event($post->ID, 'post_id');
  2226.                 if( $EM_Event->is_recurrence() ){
  2227.                         $attr['id'] = $EM_Event->get_event_recurrence()->post_id;
  2228.                 }
  2229.         }
  2230.         return gallery_shortcode($attr);
  2231. }
  2232. function em_event_gallery_override_init(){
  2233.         remove_shortcode('gallery');
  2234.         add_shortcode('gallery', 'em_event_gallery_override');
  2235. }
  2236. add_action('init','em_event_gallery_override_init', 1000); //so that plugins like JetPack don't think we're overriding gallery, we're not i swear!
  2237. ?>
clone this paste RAW Paste Data