/**
  * Toggles whether the user is checked in or not.
  *
  * @param \WP_REST_Request $request
  * @return \WP_Error|\WP_REST_Response
  */
 protected function _create_checkin_checkout_object(\WP_REST_Request $request)
 {
     $reg_id = $request->get_param('REG_ID');
     $dtt_id = $request->get_param('DTT_ID');
     $force = $request->get_param('force');
     if ($force == 'true') {
         $force = true;
     } else {
         $force = false;
     }
     $reg = \EEM_Registration::instance()->get_one_by_ID($reg_id);
     if (!$reg instanceof \EE_Registration) {
         return $this->send_response(new \WP_Error('rest_registration_toggle_checkin_invalid_id', sprintf(__('You cannot checkin registration with ID %1$s because it doesn\'t exist.', 'event_espresso'), $reg_id), array('status' => 422)));
     }
     if (!\EE_Capabilities::instance()->current_user_can('ee_edit_checkin', 'rest_api_checkin_endpoint', $reg_id)) {
         return $this->send_response(new \WP_Error('rest_user_cannot_toggle_checkin', sprintf(__('You are not allowed to checkin registration with ID %1$s.', 'event_espresso'), $reg_id), array('status' => 403)));
     }
     $success = $reg->toggle_checkin_status($dtt_id, !$force);
     if ($success === false) {
         //rely on EE_Error::add_error messages to have been added to give more data about hwy it failed
         return $this->send_response(new \WP_Error('rest_toggle_checkin_failed', __('Registration checkin failed. Please see additional error data.', 'event_espresso')));
     }
     $checkin = \EEM_Checkin::instance()->get_one(array(array('REG_ID' => $reg_id, 'DTT_ID' => $dtt_id), 'order_by' => array('CHK_timestamp' => 'DESC')));
     if (!$checkin instanceof \EE_Checkin) {
         return $this->send_response(new \WP_Error('rest_toggle_checkin_error', sprintf(__('Supposedly we created a new checkin object for registration %1$s at datetime %2$s, but we can\'t find it.', 'event_espresso'), $reg_id, $dtt_id)));
     }
     $requested_version = $this->get_requested_version($request->get_route());
     $get_request = new \WP_REST_Request('GET', \EED_Core_Rest_Api::ee_api_namespace . $requested_version . '/checkins/' . $checkin->ID());
     $get_request->set_url_params(array('id' => $checkin->ID()));
     return Read::handle_request_get_one($get_request);
 }
 /**
  * Calculates the checkin status for each datetime this registration has access to
  *
  * @param array            $wpdb_row
  * @param \WP_REST_Request $request
  * @param Base             $controller
  * @return int
  * @throws \EE_Error
  */
 public static function datetime_checkin_stati($wpdb_row, $request, $controller)
 {
     if (is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])) {
         $reg = \EEM_Registration::instance()->get_one_by_ID($wpdb_row['Registration.REG_ID']);
     } else {
         $reg = null;
     }
     if (!$reg instanceof \EE_Registration) {
         throw new \EE_Error(sprintf(__('Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found', 'event_espresso'), $wpdb_row['Registration.REG_ID'], print_r($wpdb_row, true)));
     }
     $datetime_ids = \EEM_Datetime::instance()->get_col(array(array('Ticket.TKT_ID' => $reg->ticket_ID())));
     $checkin_stati = array();
     foreach ($datetime_ids as $datetime_id) {
         $status = $reg->check_in_status_for_datetime($datetime_id);
         switch ($status) {
             case \EE_Registration::checkin_status_out:
                 $status_pretty = 'OUT';
                 break;
             case \EE_Registration::checkin_status_in:
                 $status_pretty = 'IN';
                 break;
             case \EE_Registration::checkin_status_never:
             default:
                 $status_pretty = 'NEVER';
                 break;
         }
         $checkin_stati[$datetime_id] = $status_pretty;
     }
     return $checkin_stati;
 }
 /**
  * @group 9179
  */
 public function test_get_minimum_where_conditions_during_query()
 {
     $this->new_model_obj_with_dependencies('Registration', array('REG_deleted' => true));
     $this->new_model_obj_with_dependencies('Registration', array('REG_deleted' => false));
     //count using the default where conditions, which excludes the deleted one
     $this->assertEquals(1, EEM_Registration::instance()->count());
     //count using the MINIMUM where conditions, which INCLUDES the deleted one
     $this->assertEquals(2, EEM_Registration::instance()->count(array('default_where_conditions' => 'minimum')));
 }
 /**
  * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
  * can be sent into this method and converted back into the format used for instantiating with this data handler.
  *
  * @param $data
  *
  * @return mixed
  */
 public static function convert_data_from_persistent_storage($data)
 {
     $registration = null;
     //$data['Registration'] could be either an ID (back compat) or a registration object (prepped using old system).
     if (isset($data['Registration'])) {
         $registration = $data['Registration'] instanceof EE_Registration ? $data['Registration'] : EEM_Registration::instance()->get_one_by_ID($data['Registration']);
     }
     $prepped_data = array(0 => $registration, 1 => isset($data['filter']) ? $data['filter'] : null);
     return $prepped_data;
 }
 /**
  * This returns the data property according to what is expected from the request.
  * @param $id
  * @throws EE_Error
  * @return mixed (whatever the data is returned from the message type).
  */
 protected function _get_data_from_request($id)
 {
     //get the EE_Registration from the token
     /** @type EE_Registration $registration */
     $registration = EEM_Registration::instance()->get_one(array(array('REG_url_link' => $this->token)));
     //if no registration then bail early.
     if (!$registration instanceof EE_Registration) {
         throw new EE_Error(__('Unable to complete the request because the token is invalid.', 'event_espresso'));
     }
     return $this->_get_data_to_use($registration, $id);
 }
 /**
  * @group 7965
  */
 function test_delete_registrations_with_no_transaction()
 {
     $deletable_count = 5;
     $safe_count = 8;
     $this->factory->registration->create_many($deletable_count, array('TXN_ID' => 0));
     for ($i = 0; $i < $safe_count; $i++) {
         $this->new_model_obj_with_dependencies('Registration');
     }
     $deleted = EEM_Registration::instance()->delete_registrations_with_no_transaction();
     $this->assertEquals($deletable_count, $deleted);
 }
 /**
  *    _calculate_billable_ticket_quantities_from_registrations
  * compiles a list of EE_Tickets for each event in the passed array
  *
  * @access protected
  * @param EE_Registration[] $registrations
  * @return mixed
  */
 protected function _remove_unbillable_registrations($registrations = array())
 {
     if (!empty($registrations)) {
         // these reg statuses require payment (if event is not free)
         $requires_payment = EEM_Registration::reg_statuses_that_allow_payment();
         foreach ($registrations as $key => $registration) {
             if (!$registration instanceof EE_Registration) {
                 continue;
             }
             // are we billing for this registration at this moment ?
             if (!$registration->owes_monies_and_can_pay($requires_payment) && !($registration->final_price() == 0 && in_array($registration->status_ID(), $requires_payment))) {
                 // not billable. remove it
                 unset($registrations[$key]);
             }
         }
     }
     return $registrations;
 }
 /**
  * Adds a relationship to Term_Taxonomy for each CPT_Base
  * @param string $timezone
  * @return EEM_Event
  */
 protected function __construct($timezone = null)
 {
     EE_Registry::instance()->load_model('Registration');
     $this->singular_item = __('Event', 'event_espresso');
     $this->plural_item = __('Events', 'event_espresso');
     // to remove Cancelled events from the frontend, copy the following filter to your functions.php file
     // add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
     // to remove Postponed events from the frontend, copy the following filter to your functions.php file
     // add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
     // to remove Sold Out events from the frontend, copy the following filter to your functions.php file
     //	add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
     $this->_custom_stati = apply_filters('AFEE__EEM_Event__construct___custom_stati', array(EEM_Event::cancelled => array('label' => __('Cancelled', 'event_espresso'), 'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', TRUE)), EEM_Event::postponed => array('label' => __('Postponed', 'event_espresso'), 'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', TRUE)), EEM_Event::sold_out => array('label' => __('Sold Out', 'event_espresso'), 'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', TRUE))));
     $this->_tables = array('Event_CPT' => new EE_Primary_Table('posts', 'ID'), 'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'));
     $this->_fields = array('Event_CPT' => array('EVT_ID' => new EE_Primary_Key_Int_Field('ID', __('Post ID for Event', 'event_espresso')), 'EVT_name' => new EE_Plain_Text_Field('post_title', __('Event Name', 'event_espresso'), FALSE, ''), 'EVT_desc' => new EE_Post_Content_Field('post_content', __('Event Description', 'event_espresso'), FALSE, ''), 'EVT_slug' => new EE_Slug_Field('post_name', __('Event Slug', 'event_espresso'), FALSE, ''), 'EVT_created' => new EE_Datetime_Field('post_date', __('Date/Time Event Created', 'event_espresso'), FALSE, current_time('timestamp')), 'EVT_short_desc' => new EE_Simple_HTML_Field('post_excerpt', __('Event Short Description', 'event_espresso'), FALSE, ''), 'EVT_modified' => new EE_Datetime_Field('post_modified', __('Date/Time Event Modified', 'event_espresso'), TRUE, current_time('timestamp')), 'EVT_wp_user' => new EE_Integer_Field('post_author', __('Wordpress User ID', 'event_espresso'), FALSE, 1), 'parent' => new EE_Integer_Field('post_parent', __('Event Parent ID', 'event_espresso'), TRUE), 'EVT_order' => new EE_Integer_Field('menu_order', __('Event Menu Order', 'event_espresso'), FALSE, 1), 'post_type' => new EE_WP_Post_Type_Field('espresso_events'), 'status' => new EE_WP_Post_Status_Field('post_status', __('Event Status', 'event_espresso'), FALSE, 'draft', $this->_custom_stati)), 'Event_Meta' => array('EVTM_ID' => new EE_DB_Only_Float_Field('EVTM_ID', __('Event Meta Row ID', 'event_espresso'), FALSE), 'EVT_ID_fk' => new EE_DB_Only_Int_Field('EVT_ID', __('Foreign key to Event ID from Event Meta table', 'event_espresso'), FALSE), 'EVT_display_desc' => new EE_Boolean_Field('EVT_display_desc', __('Display Description Flag', 'event_espresso'), FALSE, 1), 'EVT_display_ticket_selector' => new EE_Boolean_Field('EVT_display_ticket_selector', __('Display Ticket Selector Flag', 'event_espresso'), FALSE, 1), 'EVT_visible_on' => new EE_Datetime_Field('EVT_visible_on', __('Event Visible Date', 'event_espresso'), TRUE, current_time('timestamp')), 'EVT_additional_limit' => new EE_Integer_Field('EVT_additional_limit', __('Limit of Additional Registrations on Same Transaction', 'event_espresso'), TRUE, 10), 'EVT_default_registration_status' => new EE_Enum_Text_Field('EVT_default_registration_status', __('Default Registration Status on this Event', 'event_espresso'), FALSE, EEM_Registration::status_id_pending_payment, EEM_Registration::reg_status_array()), 'EVT_member_only' => new EE_Boolean_Field('EVT_member_only', __('Member-Only Event Flag', 'event_espresso'), FALSE, FALSE), 'EVT_phone' => new EE_Plain_Text_Field('EVT_phone', __('Event Phone Number', 'event_espresso'), FALSE), 'EVT_allow_overflow' => new EE_Boolean_Field('EVT_allow_overflow', __('Allow Overflow on Event', 'event_espresso'), FALSE, FALSE), 'EVT_timezone_string' => new EE_Plain_Text_Field('EVT_timezone_string', __('Timezone (name) for Event times', 'event_espresso'), FALSE), 'EVT_external_URL' => new EE_Plain_Text_Field('EVT_external_URL', __('URL of Event Page if hosted elsewhere', 'event_espresso'), TRUE), 'EVT_donations' => new EE_Boolean_Field('EVT_donations', __('Accept Donations?', 'event_espresso'), FALSE, FALSE)));
     $this->_model_relations = array('Registration' => new EE_Has_Many_Relation(), 'Datetime' => new EE_Has_Many_Relation(), 'Question_Group' => new EE_HABTM_Relation('Event_Question_Group'), 'Venue' => new EE_HABTM_Relation('Event_Venue'), 'Term_Taxonomy' => new EE_HABTM_Relation('Term_Relationship'), 'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'), 'Attendee' => new EE_HABTM_Relation('Registration'));
     $this->_default_where_conditions_strategy = new EE_CPT_Where_Conditions('espresso_events', 'EVTM_ID');
     parent::__construct($timezone);
 }
 function test_generate_restrictions__basic_and_others()
 {
     global $current_user;
     $current_user = $this->factory->user->create_and_get();
     //currently registrations have the 'ee_read_registrations' and 'ee_read_others_registrations' permissions
     //if that changes, this will need to be updated
     $generator = new EE_Restriction_Generator_Protected();
     $generator->_construct_finalize(EEM_Registration::instance(), EEM_Base::caps_read);
     $restrictions = $generator->generate_restrictions();
     foreach ($restrictions as $default_where_conditions) {
         $default_where_conditions->_finalize_construct(EEM_Registration::instance());
     }
     $this->assertArrayHasKey('ee_read_registrations', $restrictions);
     $this->assertInstanceOf('EE_Return_None_Where_Conditions', $restrictions['ee_read_registrations']);
     $this->assertArrayHasKey('ee_read_others_registrations', $restrictions);
     $this->assertInstanceOf('EE_Default_Where_Conditions', $restrictions['ee_read_others_registrations']);
     $this->assertEquals(array(EEM_Registration::instance()->wp_user_field_name() => get_current_user_id()), $restrictions['ee_read_others_registrations']->get_default_where_conditions());
     $this->assertEquals(2, count($restrictions));
 }
 /**
  * @group 8193
  */
 function test_fix_reg_final_price_rounding_issue()
 {
     $txn = $this->new_model_obj_with_dependencies('Transaction', array('TXN_total' => 2.99));
     $regs = array();
     for ($i = 0; $i < 3; $i++) {
         $regs[] = $this->new_model_obj_with_dependencies('Registration', array('REG_final_price' => 1, 'TXN_ID' => $txn->ID()));
     }
     //ok so there's a 1 cent difference. The REG_final_price_sum should be 1 cent more than the transaction total
     $reg_final_price_sum = EEM_Registration::instance()->sum(array(array('TXN_ID' => $txn->ID())), 'REG_final_price');
     $this->assertEquals($txn->total() + 0.01, $reg_final_price_sum);
     $reg_processor = EE_Registry::instance()->load_class('Registration_Processor');
     $success = $reg_processor->fix_reg_final_price_rounding_issue($txn);
     $this->assertTrue($success);
     $new_reg_final_price_sum = EEM_Registration::instance()->sum(array(array('TXN_ID' => $txn->ID())), 'REG_final_price');
     $this->assertEquals($txn->total(), $new_reg_final_price_sum);
     //specifically, the first reg should now be $0.99, but the others should still be $1 each
     $this->assertEquals(0.99, $regs[0]->final_price());
     $this->assertEquals(1, $regs[1]->final_price());
     $this->assertEquals(1, $regs[2]->final_price());
 }
 /**
  *  Gets the URL that the user should generally be sent back to after payment completion offiste
  *  Adds the reg_url_link in order to remember which session we were in the middle of processing
  * @param EE_Registration or int, current registration we want to link back to in the return url.
  * @param boolean $urlencode whether or not to url-encode the url (if true, you probably intend to pass
  * this string as a URL parameter itself, or maybe a post parameter)
  *  @return string URL on the current site of the thank_you page, with parameters added on to know which registration was just
  * processed in order to correctly display the payment status. And it gets URL-encoded by default
  */
 protected function _get_return_url($registration, $urlencode = false)
 {
     //if $registration is an ID instead of an EE_Registration, make it an EE_Registration
     if (!$registration instanceof EE_Registration) {
         $registration = $this->_REG->get_one_by_ID($registration);
     }
     if (empty($registration)) {
         $msg[0] = __("Cannot get Return URL for gateway. Invalid registration", 'event_espresso');
         $msg[1] = sprinf(__("Registration being used is %s.", 'event_espresso'), print_r($registration, true));
         EE_Error::add_error(implode("||", $msg), __FILE__, __FUNCTION__, __LINE__);
         return '';
     }
     //get a registration that's currently getting processed
     /*@var $registration EE_Registration */
     $url = add_query_arg(array('e_reg_url_link' => $registration->reg_url_link()), get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
     if ($urlencode) {
         $url = urlencode($url);
     }
     return $url;
 }
 /**
  * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for list table filter.
  * @param  string  $cur_date     any currently selected date can be entered here.
  * @param  string  $status       Registration status
  * @param  integer $evt_category Event Category ID if the Event Category filter is selected
  * @return string                html
  */
 public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
 {
     $_where = array();
     if (!empty($status)) {
         $_where['STS_ID'] = $status;
     }
     if ($evt_category > 0) {
         $_where['Event.Term_Taxonomy.term_id'] = $evt_category;
     }
     $regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
     //setup vals for select input helper
     $options = array(0 => array('text' => __('Select a Month/Year', 'event_espresso'), 'id' => ''));
     foreach ($regdtts as $regdtt) {
         $date = $regdtt->reg_month . ' ' . $regdtt->reg_year;
         $options[] = array('text' => $date, 'id' => $date);
     }
     return self::select_input('month_range', $options, $cur_date, '', 'wide');
 }
 /**
  * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime (via the tickets).
  * into account
  * @return int
  */
 public function update_sold()
 {
     $count_regs_for_this_datetime = EEM_Registration::instance()->count(array(array('STS_ID' => EEM_Registration::status_id_approved, 'Ticket.Datetime.DTT_ID' => $this->ID(), 'REG_deleted' => 0)));
     $this->set('DTT_sold', $count_regs_for_this_datetime);
     $this->save();
     return $count_regs_for_this_datetime;
 }
 /**
  * 	process_shortcode - ESPRESSO_EVENT_ATTENDEES - Returns a list of attendees to an event.
  *
  *
  *
  * 	[ESPRESSO_EVENT_ATTENDEES] - defaults to attendees for earliest active event, or earliest upcoming event.
  * 	[ESPRESSO_EVENT_ATTENDEES event_id=123] - attendees for specific event.
  * 	[ESPRESSO_EVENT_ATTENDEES datetime_id=245] - attendees for a specific datetime.
  * 	[ESPRESSO_EVENT_ATTENDEES ticket_id=123] - attendees for a specific ticket.
  * 	[ESPRESSO_EVENT_ATTENDEES status=all] - specific registration status (use status id) or all for all attendees
  *                                          regardless of status.  Note default is to only return approved attendees
  * 	[ESPRESSO_EVENT_ATTENDEES show_gravatar=true] - default is to not return gravatar.  Otherwise if this is set
  *                                                  then return gravatar for email address given.
  *
  *  Note: because of the relationship between event_id, ticket_id, and datetime_id. If more than one of those params
  *  is included then preference is given to the following:
  *  - event_id is used whenever its present and any others are ignored.
  *  - if no event_id then datetime is used whenever its present and any others are ignored.
  *  - otherwise ticket_id is used if present.
  *
  *  @access 	public
  *  @param 	    array 	$attributes
  *  @return 	string
  */
 public function process_shortcode($attributes = array())
 {
     //load helpers
     EE_Registry::instance()->load_helper('Event_View');
     EE_Registry::instance()->load_helper('Template');
     // merge in any attributes passed via fallback shortcode processor
     $attributes = array_merge((array) $attributes, (array) $this->_attributes);
     //set default attributes
     $default_shortcode_attributes = array('event_id' => null, 'datetime_id' => null, 'ticket_id' => null, 'status' => EEM_Registration::status_id_approved, 'show_gravatar' => false);
     // allow the defaults to be filtered
     $default_shortcode_attributes = apply_filters('EES_Espresso_Event_Attendees__process_shortcode__default_shortcode_atts', $default_shortcode_attributes);
     // grab attributes and merge with defaults, then extract
     $attributes = array_merge($default_shortcode_attributes, $attributes);
     $template_args = array('contacts' => array(), 'event' => null, 'datetime' => null, 'ticket' => null, 'show_gravatar' => $attributes['show_gravatar']);
     //start setting up the query for the contacts
     $query = array();
     $error = false;
     //what event?
     if (empty($attributes['event_id']) && empty($attributes['datetime_id']) && empty($attributes['ticket_id'])) {
         //seems like is_espresso_event_single() isn't working as expected. So using alternate method.
         if (is_single() && is_espresso_event()) {
             $event = EEH_Event_View::get_event();
             if ($event instanceof EE_Event) {
                 $template_args['event'] = $event;
                 $query[0]['Registration.EVT_ID'] = $event->ID();
             }
         } else {
             //try getting the earliest active event if none then get the
             $events = EEM_Event::instance()->get_active_events(array('limit' => 1, 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC')));
             $events = empty($events) ? EEM_Event::instance()->get_upcoming_events(array('limit' => 1, 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'))) : $events;
             $event = reset($events);
             if ($event instanceof EE_Event) {
                 $query[0]['Registration.EVT_ID'] = $event->ID();
                 $template_args['event'] = $event;
             }
         }
     } elseif (!empty($attributes['event_id'])) {
         $event = EEM_Event::instance()->get_one_by_ID($attributes['event_id']);
         if ($event instanceof EE_Event) {
             $query[0]['Registration.EVT_ID'] = $attributes['event_id'];
             $template_args['event'] = $event;
         } else {
             $error = true;
         }
     }
     //datetime?
     if (!empty($attributes['datetime_id']) && empty($attributes['event_id'])) {
         $datetime = EEM_Datetime::instance()->get_one_by_ID($attributes['datetime_id']);
         if ($datetime instanceof EE_Datetime) {
             $query[0]['Registration.Ticket.Datetime.DTT_ID'] = $attributes['datetime_id'];
             $query['default_where_conditions'] = 'this_model_only';
             $template_args['datetime'] = $datetime;
             $template_args['event'] = $datetime->event();
         } else {
             $error = true;
         }
     }
     //ticket?just
     if (!empty($attributes['ticket_id']) && empty($attributes['event_id']) && empty($attributes['datetime_id'])) {
         $ticket = EEM_Ticket::instance()->get_one_by_ID($attributes['ticket_id']);
         if ($ticket instanceof EE_Ticket) {
             $query[0]['Registration.TKT_ID'] = $attributes['ticket_id'];
             $template_args['ticket'] = $ticket;
             $template_args['event'] = $ticket->first_datetime() instanceof EE_Datetime ? $ticket->first_datetime()->event() : null;
         } else {
             $error = true;
         }
     }
     //status
     $reg_status_array = EEM_Registration::reg_status_array();
     if ($attributes['status'] != 'all' && isset($reg_status_array[$attributes['status']])) {
         $query[0]['Registration.STS_ID'] = $attributes['status'];
     }
     $query['group_by'] = array('ATT_ID');
     $query['order_by'] = apply_filters('FHEE__EES_Espresso_Event_Attendees__process_shortcode__order_by', array('ATT_lname' => 'ASC', 'ATT_fname' => 'ASC'));
     //if we have NO query where conditions, then there was an invalid parameter or the shortcode was used incorrectly
     //so when WP_DEBUG is set and true, we'll show a message, otherwise we'll just return an empty string.
     if (!isset($query[0]) || !is_array($query[0]) || $error) {
         if (WP_DEBUG) {
             return '<div class="important-notice ee-attention">' . __('The [ESPRESSO_EVENT_ATTENDEES] shortcode has been used incorrectly.  Please double check the arguments you used for any typos.  In the case of ID type arguments, its possible the given ID does not correspond to existing data in the database.', 'event_espresso') . '</div>';
         } else {
             return '';
         }
     }
     //get contacts!
     $template_args['contacts'] = EEM_Attendee::instance()->get_all($query);
     //all set let's load up the template and return.
     return EEH_Template::locate_template('loop-espresso_event_attendees.php', $template_args, true, true);
 }
 /**
  * This returns the total remaining spaces for sale on this event.
  *
  * ############################
  * VERY IMPORTANT FOR DEVELOPERS:
  * While included here, this method is still being tested internally, so its signature and behaviour COULD change. While
  * this comment block is in place, usage is at your own risk and know that it may change in future builds.
  * ############################
  *
  * @uses EE_Event::total_available_spaces()
  * @return float|int  (EE_INF is returned as float)
  */
 public function spaces_remaining_for_sale()
 {
     //first get total available spaces including consideration for tickets that have already sold.
     $spaces_available = $this->total_available_spaces(true);
     //if total available = 0, then exit right away because that means everything is expired.
     if ($spaces_available === 0) {
         return 0;
     }
     //subtract total approved registrations from spaces available to get how many are remaining.
     $spots_taken = EEM_Registration::instance()->count(array(array('EVT_ID' => $this->ID(), 'STS_ID' => EEM_Registration::status_id_approved)), 'REG_ID', true);
     $spaces_remaining = $spaces_available - $spots_taken;
     return $spaces_remaining > 0 ? $spaces_remaining : 0;
 }
 /**
  *  This runs when the msg_url_trigger route has initiated.
  *
  * @since 4.5.0
  * @param WP $WP
  * @throws EE_Error
  * @return    void
  */
 public function run($WP)
 {
     $sending_messenger = EE_Registry::instance()->REQ->is_set('snd_msgr') ? EE_Registry::instance()->REQ->get('snd_msgr') : '';
     $generating_messenger = EE_Registry::instance()->REQ->is_set('gen_msgr') ? EE_Registry::instance()->REQ->get('gen_msgr') : '';
     $message_type = EE_Registry::instance()->REQ->is_set('message_type') ? EE_Registry::instance()->REQ->get('message_type') : '';
     $context = EE_Registry::instance()->REQ->is_set('context') ? EE_Registry::instance()->REQ->get('context') : '';
     $token = EE_Registry::instance()->REQ->is_set('token') ? EE_Registry::instance()->REQ->get('token') : '';
     $data_id = EE_Registry::instance()->REQ->is_set('id') ? (int) EE_Registry::instance()->REQ->get('id') : 0;
     //verify the needed params are present.
     if (empty($sending_messenger) || empty($generating_messenger) || empty($message_type) || empty($context) || empty($token)) {
         EE_Error::add_error(__('The request for the "msg_url_trigger" route has a malformed url.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         return;
     }
     //get the registration: the token will always be the unique REG_url_link saved with a registration.  We use that to make sure we retrieve the correct data for the given registration.
     $registration = EEM_Registration::instance()->get_one(array(array('REG_url_link' => $token)));
     //if no registration then bail early.
     if (!$registration instanceof EE_Registration) {
         EE_Error::add_error(__('Unable to complete the request because the token is invalid.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         return;
     }
     //ensure controller is loaded
     self::_load_controller();
     // attempt to process message
     try {
         // retrieve the data via the handler
         //  Depending on the context and the message type data handler, the data_id will correspond to the specific data handler item we need to retrieve for specific messages
         // (i.e. a specific payment or specific refund).
         $data = $this->_get_messages_data_from_url($generating_messenger, $message_type, $registration, $data_id, $context);
         //make sure we drop generating messenger if both sending and generating are the same.
         $generating_messenger = $sending_messenger != $generating_messenger ? $generating_messenger : NULL;
         //now we can trigger the actual sending of the message via the message type.
         self::$_EEMSG->send_message($message_type, $data, $sending_messenger, $generating_messenger, $context);
     } catch (EE_Error $e) {
         $error_msg = __('Please note that a system message failed to send due to a technical issue.', 'event_espresso');
         // add specific message for developers if WP_DEBUG in on
         $error_msg .= '||' . $e->getMessage();
         EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
     }
 }
 /**
  * @since 4.8.10.rc.10
  * @group integration
  */
 public function test__set_registration_status_from_request_for_multiple_registrations()
 {
     //basically the same as the prior test except here we're testing multiple registrations.
     $registration_a = $this->factory->registration->create(array('STS_ID' => EEM_Registration::status_id_cancelled));
     $registration_b = $this->factory->registration->create(array('STS_ID' => EEM_Registration::status_id_pending_payment));
     $registration_c = $this->factory->registration->create(array('STS_ID' => EEM_Registration::status_id_not_approved));
     $expected_ids = array($registration_a->ID(), $registration_b->ID(), $registration_c->ID());
     $_REQUEST['_REG_ID'] = $expected_ids;
     $this->_load_requirements();
     $success = $this->_admin_page->set_registration_status_from_request(EEM_Registration::status_id_not_approved);
     $this->assertArrayHasKey('success', $success);
     $this->assertTrue($success['success']);
     $this->assertArrayHasKey('REG_ID', $success);
     $this->assertCount(3, $success['REG_ID']);
     $this->assertEquals($expected_ids, $success['REG_ID']);
     //verify registrations got chagned to approved (or stayed there).
     $registrations = EEM_Registration::reset()->instance()->get_all(array(array('STS_ID' => EEM_Registration::status_id_not_approved)));
     $this->assertEquals(3, count($registrations));
     $this->assertEquals($expected_ids, array_keys($registrations));
 }
 /**
  * 	get list of registration statuses
  * @access private
  * @param array $exclude
  * @return array
  */
 private function _get_registration_status_array($exclude = array())
 {
     //in the very rare circumstance that we are deleting a model's table's data
     //and the table hasn't actually been created, this could have an error
     /** @type WPDB $wpdb */
     global $wpdb;
     EE_Registry::instance()->load_helper('Activation');
     if (EEH_Activation::table_exists($wpdb->prefix . 'esp_status')) {
         $SQL = 'SELECT STS_ID, STS_code FROM ' . $wpdb->prefix . 'esp_status WHERE STS_type = "registration"';
         $results = $wpdb->get_results($SQL);
         self::$_reg_status = array();
         foreach ($results as $status) {
             if (!in_array($status->STS_ID, $exclude)) {
                 self::$_reg_status[$status->STS_ID] = $status->STS_code;
             }
         }
     }
 }
 /**
  * update registrations REG_paid field after successful payment and link registrations with payment
  *
  * @param EE_Transaction $transaction
  * @param EE_Payment $payment
  * @param EE_Registration[] $registrations
  * @throws \EE_Error
  */
 public function process_registration_payments(EE_Transaction $transaction, EE_Payment $payment, $registrations = array())
 {
     // only process if payment was successful
     if ($payment->status() !== EEM_Payment::status_id_approved) {
         return;
     }
     //EEM_Registration::instance()->show_next_x_db_queries();
     if (empty($registrations)) {
         // find registrations with monies owing that can receive a payment
         $registrations = $transaction->registrations(array(array('STS_ID' => array('IN', EEM_Registration::reg_statuses_that_allow_payment()), 'REG_final_price' => array('!=', 0), 'REG_final_price*' => array('!=', 'REG_paid', true))));
     }
     // still nothing ??!??
     if (empty($registrations)) {
         return;
     }
     // todo: break out the following logic into a separate strategy class
     // todo: named something like "Sequential_Reg_Payment_Strategy"
     // todo: which would apply payments using the capitalist "first come first paid" approach
     // todo: then have another strategy class like "Distributed_Reg_Payment_Strategy"
     // todo: which would be the socialist "everybody gets a piece of pie" approach,
     // todo: which would be better for deposits, where you want a bit of the payment applied to each registration
     $refund = $payment->is_a_refund();
     // how much is available to apply to registrations?
     $available_payment_amount = abs($payment->amount());
     foreach ($registrations as $registration) {
         if ($registration instanceof EE_Registration) {
             // nothing left?
             if ($available_payment_amount <= 0) {
                 break;
             }
             if ($refund) {
                 $available_payment_amount = $this->process_registration_refund($registration, $payment, $available_payment_amount);
             } else {
                 $available_payment_amount = $this->process_registration_payment($registration, $payment, $available_payment_amount);
             }
         }
     }
     if ($available_payment_amount > 0 && apply_filters('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', false)) {
         EE_Error::add_attention(sprintf(__('A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).', 'event_espresso'), EEH_Template::format_currency($available_payment_amount), implode(', ', array_keys($registrations)), '<br/>', EEH_Template::format_currency($payment->amount())), __FILE__, __FUNCTION__, __LINE__);
     }
 }
 protected function _pretend_added_field_onto_registration_model()
 {
     add_filter('FHEE__EEM_Registration__construct__fields', array($this, '_add_reg_paid_field'));
     EEM_Registration::reset();
 }
 /**
  * owes_monies_and_can_pay
  * whether or not this registration has monies owing and it's' status allows payment
  * @access        public
  * @param array $requires_payment
  * @return bool
  */
 public function owes_monies_and_can_pay($requires_payment = array())
 {
     // these reg statuses require payment (if event is not free)
     $requires_payment = !empty($requires_payment) ? $requires_payment : EEM_Registration::reg_statuses_that_allow_payment();
     if (in_array($this->status_ID(), $requires_payment) && $this->final_price() != 0 && $this->final_price() != $this->paid()) {
         return true;
     } else {
         return false;
     }
 }
 /**
  * delete_payment
  * 	delete a payment or refund made towards a transaction
  *
  * @access public
  *	@return void
  */
 public function delete_payment()
 {
     $json_response_data = array('return_data' => FALSE);
     $PAY_ID = isset($this->_req_data['delete_txn_admin_payment'], $this->_req_data['delete_txn_admin_payment']['PAY_ID']) ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID']) : 0;
     if ($PAY_ID) {
         $delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change']) ? $this->_req_data['delete_txn_reg_status_change'] : false;
         $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
         if ($payment instanceof EE_Payment) {
             $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
             /** @type EE_Transaction_Payments $transaction_payments */
             $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
             if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
                 EE_Error::add_success(__('The Payment was successfully deleted.', 'event_espresso'));
                 $json_response_data['return_data'] = array('PAY_ID' => $PAY_ID, 'amount' => $payment->amount(), 'total_paid' => $payment->transaction()->paid(), 'txn_status' => $payment->transaction()->status_ID(), 'pay_status' => $payment->STS_ID(), 'delete_txn_reg_status_change' => $delete_txn_reg_status_change);
                 //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
                 if (!empty($REG_IDs)) {
                     EE_Registry::instance()->load_helper('Template');
                     $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
                     foreach ($registrations as $registration) {
                         $json_response_data['return_data']['registrations'][$registration->ID()] = array('owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()), 'paid' => $registration->pretty_paid());
                     }
                 }
                 if ($delete_txn_reg_status_change) {
                     $this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
                     //MAKE sure we also add the delete_txn_req_status_change to the
                     //$_REQUEST global because that's how messages will be looking
                     //for it.
                     $_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
                     $this->_process_registration_status_change($payment->transaction());
                 }
             }
         } else {
             EE_Error::add_error(__('Valid Payment data could not be retrieved from the database.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         }
     } else {
         $msg = __('A valid Payment ID was not received, therefore payment form data could not be loaded.', 'event_espresso');
         EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
     }
     $notices = EE_Error::get_notices(FALSE, FALSE, FALSE);
     echo json_encode(array_merge($json_response_data, $notices));
     die;
 }
 /**
  * This duplicates the attendee object for the given incoming registration id and attendee_id.
  * @return void
  */
 protected function _duplicate_attendee()
 {
     $action = !empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
     //verify we have necessary info
     if (empty($this->_req_data['_REG_ID'])) {
         EE_Error::add_error(__('Unable to create the contact for the registration because the required paramaters are not present (_REG_ID )', 'event_espresso'), __FILE__, __LINE__, __FUNCTION__);
         $query_args = array('action' => $action);
         $this->_redirect_after_action('', '', '', $query_args, TRUE);
     }
     //okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
     $registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
     $attendee = $registration->attendee();
     //remove relation of existing attendee on registration
     $registration->_remove_relation_to($attendee, 'Attendee');
     //new attendee
     $new_attendee = clone $attendee;
     $new_attendee->set('ATT_ID', 0);
     $new_attendee->save();
     //add new attendee to reg
     $registration->_add_relation_to($new_attendee, 'Attendee');
     EE_Error::add_success(__('New Contact record created.  Now make any edits you wish to make for this contact.', 'event_espresso'));
     //redirect to edit page for attendee
     $query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
     $this->_redirect_after_action('', '', '', $query_args, TRUE);
 }
 /**
  * This method checks for registration IDs in the request via the given key and creates the messages to generate
  * objects from them, then returns the array of messages to generate objects.
  * Note, this sets up registrations for the registration family of message types.
  *
  * @param string $registration_ids_key  This is used to indicate what represents the registration ids in the request.
  *
  * @return EE_Message_To_Generate[]
  */
 public function setup_messages_to_generate_from_registration_ids_in_request($registration_ids_key = '_REG_ID')
 {
     EE_Registry::instance()->load_core('Request_Handler');
     EE_Registry::instance()->load_helper('MSG_Template');
     $regs_to_send = array();
     $regIDs = EE_Registry::instance()->REQ->get($registration_ids_key);
     if (empty($regIDs)) {
         EE_Error::add_error(__('Something went wrong because we\'re missing the registration ID', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         return false;
     }
     //make sure is an array
     $regIDs = is_array($regIDs) ? $regIDs : array($regIDs);
     foreach ($regIDs as $regID) {
         $reg = EEM_Registration::instance()->get_one_by_ID($regID);
         if (!$reg instanceof EE_Registration) {
             EE_Error::add_error(sprintf(__('Unable to retrieve a registration object for the given reg id (%s)', 'event_espresso'), $regID));
             return false;
         }
         $regs_to_send[$reg->transaction_ID()][$reg->status_ID()][] = $reg;
     }
     $messages_to_generate = array();
     foreach ($regs_to_send as $status_group) {
         foreach ($status_group as $status_id => $registrations) {
             $messages_to_generate = array_merge($messages_to_generate, $this->setup_mtgs_for_all_active_messengers(EEH_MSG_Template::convert_reg_status_to_message_type($status_id), array($registrations, $status_id)));
         }
     }
     return $messages_to_generate;
 }
 /**
  * Returns the payment method used for the last payment made for a registration.
  *
  * Note: if an offline payment method was selected on the related transaction then this will have no payment methods returned.
  * It will ONLY return a payment method for a PAYMENT recorded against the registration.
  *
  * @param EE_Registration|int $registration_or_reg_id  Either the EE_Registration object or the id for the registration.
  * @return EE_Payment|null
  */
 public function get_last_used_for_registration($registration_or_reg_id)
 {
     $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
     $query_params = array(0 => array('Payment.Registration.REG_ID' => $registration_id), 'order_by' => array('Payment.PAY_ID' => 'DESC'));
     return $this->get_one($query_params);
 }
 /**
  * Counts total unit to process
  *
  * @param int $event_id
  * @return int
  */
 public function count_units_to_process($event_id)
 {
     //use the legacy filter
     $query_params = apply_filters('FHEE__EE_Export__report_registration_for_event', array(array('OR' => array('Transaction.STS_ID' => array('NOT IN', array(\EEM_Transaction::failed_status_code, \EEM_Transaction::abandoned_status_code)), 'STS_ID' => \EEM_Registration::status_id_approved), 'Ticket.TKT_deleted' => array('IN', array(true, false))), 'order_by' => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'), 'force_join' => array('Transaction', 'Ticket', 'Attendee')), $event_id);
     if ($event_id) {
         $query_params[0]['EVT_ID'] = $event_id;
     } else {
         $query_params['force_join'][] = 'Event';
     }
     return \EEM_Registration::instance()->count($query_params);
 }
 /**
  * @param string $default_reg_status
  */
 public static function set_default_reg_status($default_reg_status)
 {
     self::$_default_reg_status = $default_reg_status;
     //if EEM_Event has already been instantiated, then we need to reset the `EVT_default_reg_status` field to use the new default.
     if (self::$_instance instanceof EEM_Event) {
         self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = new EE_Enum_Text_Field('EVT_default_registration_status', __('Default Registration Status on this Event', 'event_espresso'), false, $default_reg_status, EEM_Registration::reg_status_array());
         self::$_instance->_fields['Event_Meta']['EVT_default_registration_status']->_construct_finalize('Event_Meta', 'EVT_default_registration_status', 'EEM_Event');
     }
 }
 public function column_attendees($item)
 {
     $attendees_query_args = array('action' => 'default', 'event_id' => $item->ID());
     $attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
     $registered_attendees = EEM_Registration::instance()->get_event_registration_count($item->ID());
     return '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>';
 }
 protected function _parser($shortcode)
 {
     EE_Registry::instance()->load_helper('Formatter');
     $this->_event = $this->_data instanceof EE_Event ? $this->_data : null;
     //if no event, then let's see if there is a reg_obj.  If there IS, then we'll try and grab the event from the reg_obj instead.
     if (empty($this->_event)) {
         $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : NULL;
         $aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee;
         $this->_event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration ? $aee->reg_obj->event() : NULL;
     }
     //If there is no event objecdt by now then get out.
     if (!$this->_event instanceof EE_Event) {
         return '';
     }
     switch ($shortcode) {
         case '[EVENT_ID]':
             return $this->_event->ID();
             break;
         case '[EVENT_IDENTIFIER]':
             return isset($this->_data['line_ref']) ? $this->_data['line_ref'] : '';
             break;
         case '[EVENT]':
         case '[EVENT_NAME]':
             return $this->_event->get('EVT_name');
             break;
         case '[EVENT_PHONE]':
             return $this->_event->get('EVT_phone');
             break;
         case '[EVENT_DESCRIPTION]':
             return $this->_event->get('EVT_desc');
             break;
         case '[EVENT_EXCERPT]':
             return $this->_event->get('EVT_short_desc');
             break;
         case '[EVENT_LINK]':
             return $this->_get_event_link($this->_event);
             break;
         case '[EVENT_URL]':
             return $this->_get_event_link($this->_event, FALSE);
             break;
         case '[VIRTUAL_URL]':
             $venue = $this->_event->get_first_related('Venue');
             if (empty($venue)) {
                 return '';
             }
             return $venue->get('VNU_virtual_url');
         case '[VIRTUAL_PHONE]':
             $venue = $this->_event->get_first_related('Venue');
             if (empty($venue)) {
                 return '';
             }
             return $venue->get('VNU_virtual_phone');
             break;
         case '[EVENT_IMAGE]':
             $image = $this->_event->feature_image_url(array(600, 300));
             // @todo: eventually we should make this an attribute shortcode so that em can send along what size they want returned.
             return !empty($image) ? '<img src="' . $image . '" alt="' . sprintf(esc_attr__('%s Feature Image', 'event_espresso'), $this->_event->get('EVT_name')) . '" />' : '';
             break;
         case '[EVENT_FACEBOOK_URL]':
             $facebook_url = $this->_event->get_post_meta('event_facebook', true);
             return empty($facebook_url) ? EE_Registry::instance()->CFG->organization->get_pretty('facebook') : $facebook_url;
             break;
         case '[EVENT_TWITTER_URL]':
             $twitter_url = $this->_event->get_post_meta('event_twitter', true);
             return empty($twitter_url) ? EE_Registry::instance()->CFG->organization->get_pretty('twitter') : $twitter_url;
             break;
         case '[EVENT_AUTHOR_EMAIL]':
             $author_id = $this->_event->get('EVT_wp_user');
             $user_data = get_userdata((int) $author_id);
             return $user_data->user_email;
             break;
         case '[EVENT_TOTAL_SPOTS_TAKEN]':
             return EEM_Registration::instance()->count(array(array('EVT_ID' => $this->_event->ID(), 'STS_ID' => EEM_Registration::status_id_approved)), 'REG_ID', true);
             break;
         case '[REGISTRATION_LIST_TABLE_FOR_EVENT_URL]':
             EE_Registry::instance()->load_helper('URL');
             return EEH_URL::add_query_args_and_nonce(array('event_id' => $this->_event->ID(), 'page' => 'espresso_registrations', 'action' => 'default'), admin_url('admin.php'), true);
             break;
     }
     if (strpos($shortcode, '[EVENT_META_*') !== false) {
         $shortcode = str_replace('[EVENT_META_*', '', $shortcode);
         $shortcode = trim(str_replace(']', '', $shortcode));
         //pull the meta value from the event post
         $event_meta = $this->_event->get_post_meta($shortcode, true);
         return !empty($event_meta) ? $this->_event->get_post_meta($shortcode, true) : '';
     }
     if (strpos($shortcode, '[EVENT_TOTAL_AVAILABLE_SPACES_*') !== false) {
         $attrs = $this->_get_shortcode_attrs($shortcode);
         $method = empty($attrs['method']) ? 'current' : $attrs['method'];
         $method = $method === 'current';
         $available = $this->_event->total_available_spaces($method);
         return $available === INF ? '&infin;' : $available;
     }
     return '';
 }
 /**
  * @param $elements
  * @return array
  */
 public function dashboard_glance_items($elements)
 {
     $events = EEM_Event::instance()->count();
     $items['events']['url'] = EE_Admin_Page::add_query_args_and_nonce(array('page' => 'espresso_events'), admin_url('admin.php'));
     $items['events']['text'] = sprintf(_n('%s Event', '%s Events', $events), number_format_i18n($events));
     $items['events']['title'] = __('Click to view all Events', 'event_espresso');
     $registrations = EEM_Registration::instance()->count(array(array('STS_ID' => array('!=', EEM_Registration::status_id_incomplete))));
     $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce(array('page' => 'espresso_registrations'), admin_url('admin.php'));
     $items['registrations']['text'] = sprintf(_n('%s Registration', '%s Registrations', $registrations), number_format_i18n($registrations));
     $items['registrations']['title'] = __('Click to view all registrations', 'event_espresso');
     $items = apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
     foreach ($items as $type => $item_properties) {
         $elements[] = sprintf('<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>', $item_properties['url'], $item_properties['title'], $item_properties['text']);
     }
     return $elements;
 }