Completed
Branch FET-10766-extract-activation-d... (2c1e01)
by
unknown
84:57 queued 73:57
created
core/EED_Module.module.php 1 patch
Indentation   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -14,121 +14,121 @@
 block discarded – undo
14 14
 abstract class EED_Module extends EE_Configurable implements ResettableInterface
15 15
 {
16 16
 
17
-    /**
18
-     * rendered output to be returned to WP
19
-     *
20
-     * @var    string $output
21
-     */
22
-    protected $output = '';
23
-
24
-    /**
25
-     * the current active espresso template theme
26
-     *
27
-     * @var    string $theme
28
-     */
29
-    protected $theme = '';
30
-
31
-
32
-
33
-    /**
34
-     * @return void
35
-     */
36
-    public static function reset()
37
-    {
38
-        $module_name = get_called_class();
39
-        new $module_name();
40
-    }
41
-
42
-
43
-
44
-    /**
45
-     *    set_hooks - for hooking into EE Core, other modules, etc
46
-     *
47
-     * @access    public
48
-     * @return    void
49
-     */
50
-    public static function set_hooks()
51
-    {
52
-    }
53
-
54
-
55
-
56
-    /**
57
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
58
-     *
59
-     * @access    public
60
-     * @return    void
61
-     */
62
-    public static function set_hooks_admin()
63
-    {
64
-    }
65
-
66
-
67
-
68
-    /**
69
-     *    run - initial module setup
70
-     *    this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
71
-     *
72
-     * @access    public
73
-     * @var            WP $WP
74
-     * @return    void
75
-     */
76
-    abstract public function run($WP);
77
-
78
-
79
-
80
-    /**
81
-     * EED_Module constructor.
82
-     */
83
-    final public function __construct()
84
-    {
85
-        $this->theme = EE_Config::get_current_theme();
86
-        $module_name = $this->module_name();
87
-        EE_Registry::instance()->modules->{$module_name} = $this;
88
-    }
89
-
90
-
91
-
92
-    /**
93
-     * @param $module_name
94
-     * @return EED_Module
95
-     */
96
-    protected static function get_instance($module_name = '')
97
-    {
98
-        $module_name = ! empty($module_name)
99
-            ? $module_name
100
-            : get_called_class();
101
-        if (
102
-            ! isset(EE_Registry::instance()->modules->{$module_name})
103
-            || ! EE_Registry::instance()->modules->{$module_name} instanceof EED_Module
104
-        ) {
105
-            EE_Registry::instance()->add_module($module_name);
106
-        }
107
-        return EE_Registry::instance()->get_module($module_name);
108
-    }
109
-
110
-
111
-
112
-    /**
113
-     *    module_name
114
-     *
115
-     * @access    public
116
-     * @return    string
117
-     */
118
-    public function module_name()
119
-    {
120
-        return get_class($this);
121
-    }
122
-
123
-
124
-
125
-    /**
126
-     * @return string
127
-     */
128
-    public function theme()
129
-    {
130
-        return $this->theme;
131
-    }
17
+	/**
18
+	 * rendered output to be returned to WP
19
+	 *
20
+	 * @var    string $output
21
+	 */
22
+	protected $output = '';
23
+
24
+	/**
25
+	 * the current active espresso template theme
26
+	 *
27
+	 * @var    string $theme
28
+	 */
29
+	protected $theme = '';
30
+
31
+
32
+
33
+	/**
34
+	 * @return void
35
+	 */
36
+	public static function reset()
37
+	{
38
+		$module_name = get_called_class();
39
+		new $module_name();
40
+	}
41
+
42
+
43
+
44
+	/**
45
+	 *    set_hooks - for hooking into EE Core, other modules, etc
46
+	 *
47
+	 * @access    public
48
+	 * @return    void
49
+	 */
50
+	public static function set_hooks()
51
+	{
52
+	}
53
+
54
+
55
+
56
+	/**
57
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
58
+	 *
59
+	 * @access    public
60
+	 * @return    void
61
+	 */
62
+	public static function set_hooks_admin()
63
+	{
64
+	}
65
+
66
+
67
+
68
+	/**
69
+	 *    run - initial module setup
70
+	 *    this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
71
+	 *
72
+	 * @access    public
73
+	 * @var            WP $WP
74
+	 * @return    void
75
+	 */
76
+	abstract public function run($WP);
77
+
78
+
79
+
80
+	/**
81
+	 * EED_Module constructor.
82
+	 */
83
+	final public function __construct()
84
+	{
85
+		$this->theme = EE_Config::get_current_theme();
86
+		$module_name = $this->module_name();
87
+		EE_Registry::instance()->modules->{$module_name} = $this;
88
+	}
89
+
90
+
91
+
92
+	/**
93
+	 * @param $module_name
94
+	 * @return EED_Module
95
+	 */
96
+	protected static function get_instance($module_name = '')
97
+	{
98
+		$module_name = ! empty($module_name)
99
+			? $module_name
100
+			: get_called_class();
101
+		if (
102
+			! isset(EE_Registry::instance()->modules->{$module_name})
103
+			|| ! EE_Registry::instance()->modules->{$module_name} instanceof EED_Module
104
+		) {
105
+			EE_Registry::instance()->add_module($module_name);
106
+		}
107
+		return EE_Registry::instance()->get_module($module_name);
108
+	}
109
+
110
+
111
+
112
+	/**
113
+	 *    module_name
114
+	 *
115
+	 * @access    public
116
+	 * @return    string
117
+	 */
118
+	public function module_name()
119
+	{
120
+		return get_class($this);
121
+	}
122
+
123
+
124
+
125
+	/**
126
+	 * @return string
127
+	 */
128
+	public function theme()
129
+	{
130
+		return $this->theme;
131
+	}
132 132
 
133 133
 
134 134
 
Please login to merge, or discard this patch.
core/helpers/EEH_Schema.helper.php 2 patches
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -17,74 +17,74 @@  discard block
 block discarded – undo
17 17
 class EEH_Schema {
18 18
 
19 19
 
20
-    /**
21
-     * generates JSON-based linked data for an event
22
-     *
23
-     * @param EE_Event $event
24
-     * @throws EE_Error
25
-     */
26
-    public static function add_json_linked_data_for_event(EE_Event $event)
27
-    {
28
-    	//Check we have a valid datetime for the event
29
-    	if(! $event->primary_datetime() instanceof EE_Datetime) {
30
-    		return;
31
-    	}
32
-
33
-        $template_args = array(
34
-            'event_permalink' => '',
35
-            'event_name' => '',
36
-            'event_description' => '',
37
-            'event_start' => '',
38
-            'event_end' => '',
39
-            'currency' => '',
40
-            'event_tickets' => array(),
41
-            'venue_name' => '',
42
-            'venue_url' => '',
43
-            'venue_locality' => '',
44
-            'venue_region' => '',
45
-            'event_image' => '',
46
-        );
47
-        $template_args['event_permalink'] = $event->get_permalink();
48
-        $template_args['event_name'] = $event->name();
49
-        $template_args['event_description'] = wp_strip_all_tags($event->short_description(200));
50
-        // clone datetime so that date formats don't override those for the original datetime
51
-        $primary_datetime = clone $event->primary_datetime();
52
-        $template_args['event_start'] = $primary_datetime->start_date(DateTime::ATOM);
53
-        $template_args['event_end'] = $primary_datetime->end_date(DateTime::ATOM);
54
-        unset($primary_datetime);
55
-        $template_args['currency'] = EE_Registry::instance()->CFG->currency->code;
56
-        foreach ($event->tickets() as $original_ticket) {
57
-            // clone tickets so that date formats don't override those for the original ticket
58
-            $ticket= clone $original_ticket;
59
-            $ID = $ticket->ID();
60
-            $template_args['event_tickets'][$ID]['start_date'] = $ticket->start_date(DateTime::ATOM, null);
61
-            $template_args['event_tickets'][$ID]['end_date'] = $ticket->end_date(DateTime::ATOM, null);
62
-            $template_args['event_tickets'][$ID]['price'] = number_format(
63
-                $ticket->price(),
64
-                EE_Registry::instance()->CFG->currency->dec_plc,
65
-                EE_Registry::instance()->CFG->currency->dec_mrk,
66
-                EE_Registry::instance()->CFG->currency->thsnds
67
-            );
68
-            unset($ticket);
69
-        }
70
-        $VNU_ID = espresso_venue_id();
71
-        if ( ! empty($VNU_ID) && ! espresso_is_venue_private($VNU_ID)) {
72
-            $venue = EEH_Venue_View::get_venue($VNU_ID);
73
-            $template_args['venue_name'] = get_the_title($VNU_ID);
74
-            $template_args['venue_url'] = get_permalink($VNU_ID);
75
-            $template_args['venue_locality'] = $venue->city();
76
-            $template_args['venue_region'] = $venue->state_name();
77
-        }
78
-        $template_args['event_image'] = $event->feature_image_url();
79
-        $template_args = apply_filters(
80
-            'FHEE__EEH_Schema__add_json_linked_data_for_event__template_args',
81
-            $template_args,
82
-            $event,
83
-            $VNU_ID
84
-        );
85
-        extract($template_args, EXTR_OVERWRITE);
86
-        include EE_TEMPLATES . 'json_linked_data_for_event.template.php';
87
-    }
20
+	/**
21
+	 * generates JSON-based linked data for an event
22
+	 *
23
+	 * @param EE_Event $event
24
+	 * @throws EE_Error
25
+	 */
26
+	public static function add_json_linked_data_for_event(EE_Event $event)
27
+	{
28
+		//Check we have a valid datetime for the event
29
+		if(! $event->primary_datetime() instanceof EE_Datetime) {
30
+			return;
31
+		}
32
+
33
+		$template_args = array(
34
+			'event_permalink' => '',
35
+			'event_name' => '',
36
+			'event_description' => '',
37
+			'event_start' => '',
38
+			'event_end' => '',
39
+			'currency' => '',
40
+			'event_tickets' => array(),
41
+			'venue_name' => '',
42
+			'venue_url' => '',
43
+			'venue_locality' => '',
44
+			'venue_region' => '',
45
+			'event_image' => '',
46
+		);
47
+		$template_args['event_permalink'] = $event->get_permalink();
48
+		$template_args['event_name'] = $event->name();
49
+		$template_args['event_description'] = wp_strip_all_tags($event->short_description(200));
50
+		// clone datetime so that date formats don't override those for the original datetime
51
+		$primary_datetime = clone $event->primary_datetime();
52
+		$template_args['event_start'] = $primary_datetime->start_date(DateTime::ATOM);
53
+		$template_args['event_end'] = $primary_datetime->end_date(DateTime::ATOM);
54
+		unset($primary_datetime);
55
+		$template_args['currency'] = EE_Registry::instance()->CFG->currency->code;
56
+		foreach ($event->tickets() as $original_ticket) {
57
+			// clone tickets so that date formats don't override those for the original ticket
58
+			$ticket= clone $original_ticket;
59
+			$ID = $ticket->ID();
60
+			$template_args['event_tickets'][$ID]['start_date'] = $ticket->start_date(DateTime::ATOM, null);
61
+			$template_args['event_tickets'][$ID]['end_date'] = $ticket->end_date(DateTime::ATOM, null);
62
+			$template_args['event_tickets'][$ID]['price'] = number_format(
63
+				$ticket->price(),
64
+				EE_Registry::instance()->CFG->currency->dec_plc,
65
+				EE_Registry::instance()->CFG->currency->dec_mrk,
66
+				EE_Registry::instance()->CFG->currency->thsnds
67
+			);
68
+			unset($ticket);
69
+		}
70
+		$VNU_ID = espresso_venue_id();
71
+		if ( ! empty($VNU_ID) && ! espresso_is_venue_private($VNU_ID)) {
72
+			$venue = EEH_Venue_View::get_venue($VNU_ID);
73
+			$template_args['venue_name'] = get_the_title($VNU_ID);
74
+			$template_args['venue_url'] = get_permalink($VNU_ID);
75
+			$template_args['venue_locality'] = $venue->city();
76
+			$template_args['venue_region'] = $venue->state_name();
77
+		}
78
+		$template_args['event_image'] = $event->feature_image_url();
79
+		$template_args = apply_filters(
80
+			'FHEE__EEH_Schema__add_json_linked_data_for_event__template_args',
81
+			$template_args,
82
+			$event,
83
+			$VNU_ID
84
+		);
85
+		extract($template_args, EXTR_OVERWRITE);
86
+		include EE_TEMPLATES . 'json_linked_data_for_event.template.php';
87
+	}
88 88
 
89 89
 
90 90
 	/**
@@ -98,8 +98,8 @@  discard block
 block discarded – undo
98 98
 	 */
99 99
 	public static function location( $location = null ) {
100 100
 		return ! empty( $location ) ? '<div itemprop="location" itemscope itemtype="http://schema.org/Place">'
101
-		                              . $location
102
-		                              . '</div>' : '';
101
+									  . $location
102
+									  . '</div>' : '';
103 103
 	}
104 104
 
105 105
 
@@ -219,8 +219,8 @@  discard block
 block discarded – undo
219 219
 	 */
220 220
 	public static function postalCode( EEI_Address $obj_with_address = null ) {
221 221
 		return $obj_with_address->zip() !== null && $obj_with_address->zip() !== '' ? '<span itemprop="postalCode">'
222
-		                                                                              . $obj_with_address->zip()
223
-		                                                                              . '</span>' : '';
222
+																					  . $obj_with_address->zip()
223
+																					  . '</span>' : '';
224 224
 	}
225 225
 
226 226
 
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 		//Check the URL includes a scheme
255 255
 		$parsed_url = parse_url($url);
256 256
 		if ( empty($parsed_url['scheme']) ) {
257
-		    $url = 'http://' . ltrim($url, '/');
257
+			$url = 'http://' . ltrim($url, '/');
258 258
 		}
259 259
 
260 260
 		$atts = '';
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
4
-	exit( 'No direct script access allowed' );
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4
+	exit('No direct script access allowed');
5 5
 }
6 6
 
7 7
 
@@ -26,7 +26,7 @@  discard block
 block discarded – undo
26 26
     public static function add_json_linked_data_for_event(EE_Event $event)
27 27
     {
28 28
     	//Check we have a valid datetime for the event
29
-    	if(! $event->primary_datetime() instanceof EE_Datetime) {
29
+    	if ( ! $event->primary_datetime() instanceof EE_Datetime) {
30 30
     		return;
31 31
     	}
32 32
 
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
         $template_args['currency'] = EE_Registry::instance()->CFG->currency->code;
56 56
         foreach ($event->tickets() as $original_ticket) {
57 57
             // clone tickets so that date formats don't override those for the original ticket
58
-            $ticket= clone $original_ticket;
58
+            $ticket = clone $original_ticket;
59 59
             $ID = $ticket->ID();
60 60
             $template_args['event_tickets'][$ID]['start_date'] = $ticket->start_date(DateTime::ATOM, null);
61 61
             $template_args['event_tickets'][$ID]['end_date'] = $ticket->end_date(DateTime::ATOM, null);
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
             $VNU_ID
84 84
         );
85 85
         extract($template_args, EXTR_OVERWRITE);
86
-        include EE_TEMPLATES . 'json_linked_data_for_event.template.php';
86
+        include EE_TEMPLATES.'json_linked_data_for_event.template.php';
87 87
     }
88 88
 
89 89
 
@@ -96,8 +96,8 @@  discard block
 block discarded – undo
96 96
 	 * @param string $location
97 97
 	 * @return string
98 98
 	 */
99
-	public static function location( $location = null ) {
100
-		return ! empty( $location ) ? '<div itemprop="location" itemscope itemtype="http://schema.org/Place">'
99
+	public static function location($location = null) {
100
+		return ! empty($location) ? '<div itemprop="location" itemscope itemtype="http://schema.org/Place">'
101 101
 		                              . $location
102 102
 		                              . '</div>' : '';
103 103
 	}
@@ -112,8 +112,8 @@  discard block
 block discarded – undo
112 112
 	 * @param string $name
113 113
 	 * @return string
114 114
 	 */
115
-	public static function name( $name = null ) {
116
-		return ! empty( $name ) ? '<span itemprop="name">' . $name . '</span>' : '';
115
+	public static function name($name = null) {
116
+		return ! empty($name) ? '<span itemprop="name">'.$name.'</span>' : '';
117 117
 	}
118 118
 
119 119
 
@@ -126,9 +126,9 @@  discard block
 block discarded – undo
126 126
 	 * @param EEI_Address $obj_with_address
127 127
 	 * @return string
128 128
 	 */
129
-	public static function streetAddress( EEI_Address $obj_with_address = null ) {
129
+	public static function streetAddress(EEI_Address $obj_with_address = null) {
130 130
 		return $obj_with_address->address() !== null && $obj_with_address->address() !== ''
131
-			? '<span itemprop="streetAddress">' . $obj_with_address->address() . '</span>' : '';
131
+			? '<span itemprop="streetAddress">'.$obj_with_address->address().'</span>' : '';
132 132
 	}
133 133
 
134 134
 
@@ -141,14 +141,14 @@  discard block
 block discarded – undo
141 141
 	 * @param EEI_Address $obj_with_address
142 142
 	 * @return string
143 143
 	 */
144
-	public static function postOfficeBoxNumber( EEI_Address $obj_with_address = null ) {
144
+	public static function postOfficeBoxNumber(EEI_Address $obj_with_address = null) {
145 145
 		// regex check for some form of PO Box or P.O. Box, etc, etc, etc
146
-		if ( preg_match(
146
+		if (preg_match(
147 147
 			"/^\s*((P(OST)?.?\s*(O(FF(ICE)?)?)?.?\s+(B(IN|OX))?)|B(IN|OX))/i",
148 148
 			$obj_with_address->address2()
149
-		) ) {
149
+		)) {
150 150
 			return $obj_with_address->address2() !== null && $obj_with_address->address2() !== ''
151
-				? '<span itemprop="postOfficeBoxNumber">' . $obj_with_address->address2() . '</span>' : '';
151
+				? '<span itemprop="postOfficeBoxNumber">'.$obj_with_address->address2().'</span>' : '';
152 152
 		} else {
153 153
 			return $obj_with_address->address2();
154 154
 		}
@@ -164,9 +164,9 @@  discard block
 block discarded – undo
164 164
 	 * @param EEI_Address $obj_with_address
165 165
 	 * @return string
166 166
 	 */
167
-	public static function addressLocality( EEI_Address $obj_with_address = null ) {
167
+	public static function addressLocality(EEI_Address $obj_with_address = null) {
168 168
 		return $obj_with_address->city() !== null && $obj_with_address->city() !== ''
169
-			? '<span itemprop="addressLocality">' . $obj_with_address->city() . '</span>' : '';
169
+			? '<span itemprop="addressLocality">'.$obj_with_address->city().'</span>' : '';
170 170
 	}
171 171
 
172 172
 
@@ -179,10 +179,10 @@  discard block
 block discarded – undo
179 179
 	 * @param EEI_Address $obj_with_address
180 180
 	 * @return string
181 181
 	 */
182
-	public static function addressRegion( EEI_Address $obj_with_address = null ) {
182
+	public static function addressRegion(EEI_Address $obj_with_address = null) {
183 183
 		$state = $obj_with_address->state_name();
184
-		if ( ! empty( $state ) ) {
185
-			return '<span itemprop="addressRegion">' . $state . '</span>';
184
+		if ( ! empty($state)) {
185
+			return '<span itemprop="addressRegion">'.$state.'</span>';
186 186
 		} else {
187 187
 			return '';
188 188
 		}
@@ -198,10 +198,10 @@  discard block
 block discarded – undo
198 198
 	 * @param EEI_Address $obj_with_address
199 199
 	 * @return string
200 200
 	 */
201
-	public static function addressCountry( EEI_Address $obj_with_address = null ) {
201
+	public static function addressCountry(EEI_Address $obj_with_address = null) {
202 202
 		$country = $obj_with_address->country_name();
203
-		if ( ! empty( $country ) ) {
204
-			return '<span itemprop="addressCountry">' . $country . '</span>';
203
+		if ( ! empty($country)) {
204
+			return '<span itemprop="addressCountry">'.$country.'</span>';
205 205
 		} else {
206 206
 			return '';
207 207
 		}
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
 	 * @param EEI_Address $obj_with_address
218 218
 	 * @return string
219 219
 	 */
220
-	public static function postalCode( EEI_Address $obj_with_address = null ) {
220
+	public static function postalCode(EEI_Address $obj_with_address = null) {
221 221
 		return $obj_with_address->zip() !== null && $obj_with_address->zip() !== '' ? '<span itemprop="postalCode">'
222 222
 		                                                                              . $obj_with_address->zip()
223 223
 		                                                                              . '</span>' : '';
@@ -233,8 +233,8 @@  discard block
 block discarded – undo
233 233
 	 * @param string $phone_nmbr
234 234
 	 * @return string
235 235
 	 */
236
-	public static function telephone( $phone_nmbr = null ) {
237
-		return $phone_nmbr !== null && $phone_nmbr !== '' ? '<span itemprop="telephone">' . $phone_nmbr . '</span>'
236
+	public static function telephone($phone_nmbr = null) {
237
+		return $phone_nmbr !== null && $phone_nmbr !== '' ? '<span itemprop="telephone">'.$phone_nmbr.'</span>'
238 238
 			: '';
239 239
 	}
240 240
 
@@ -250,19 +250,19 @@  discard block
 block discarded – undo
250 250
 	 * @param array  $attributes - array of additional link attributes in  attribute_name => value pairs. ie: array( 'title' => 'click here', 'class' => 'link-class' )
251 251
 	 * @return string (link)
252 252
 	 */
253
-	public static function url( $url = null, $text = null, $attributes = array() ) {
253
+	public static function url($url = null, $text = null, $attributes = array()) {
254 254
 		//Check the URL includes a scheme
255 255
 		$parsed_url = parse_url($url);
256
-		if ( empty($parsed_url['scheme']) ) {
257
-		    $url = 'http://' . ltrim($url, '/');
256
+		if (empty($parsed_url['scheme'])) {
257
+		    $url = 'http://'.ltrim($url, '/');
258 258
 		}
259 259
 
260 260
 		$atts = '';
261
-		foreach ( $attributes as $attribute => $value ) {
262
-			$atts .= ' ' . $attribute . '="' . $value . '"';
261
+		foreach ($attributes as $attribute => $value) {
262
+			$atts .= ' '.$attribute.'="'.$value.'"';
263 263
 		}
264 264
 		$text = $text !== null && $text !== '' ? $text : $url;
265
-		return $url !== null && $url !== '' ? '<a itemprop="url" href="' . $url . '"' . $atts . '>' . $text . '</a>'
265
+		return $url !== null && $url !== '' ? '<a itemprop="url" href="'.$url.'"'.$atts.'>'.$text.'</a>'
266 266
 			: '';
267 267
 	}
268 268
 
Please login to merge, or discard this patch.
form_sections/strategies/display/EE_Number_Input_Display_Strategy.php 2 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -64,6 +64,9 @@
 block discarded – undo
64 64
     }
65 65
 
66 66
 
67
+    /**
68
+     * @param string $argument_label
69
+     */
67 70
     private function throwValidationException($argument_label, $argument_value)
68 71
     {
69 72
         throw new InvalidArgumentException(
Please login to merge, or discard this patch.
Indentation   +105 added lines, -105 removed lines patch added patch discarded remove patch
@@ -14,111 +14,111 @@
 block discarded – undo
14 14
 class EE_Number_Input_Display_Strategy extends EE_Display_Strategy_Base
15 15
 {
16 16
 
17
-    /**
18
-     * minimum value for number field
19
-     *
20
-     * @var int|null $min
21
-     */
22
-    protected $min;
23
-
24
-    /**
25
-     * maximum value for number field
26
-     *
27
-     * @var int|null $max
28
-     */
29
-    protected $max;
30
-
31
-
32
-    /**
33
-     * This is used to set the "step" attribute for the html5 number input.
34
-     * Controls the increments on the input when incrementing or decrementing the value.
35
-     * Note:  Although the step attribute allows for the string "any" to be used, Firefox and Chrome will interpret that
36
-     * to increment by 1.  So although "any" is accepted as a value, it is converted to 1.
37
-     * @var float
38
-     */
39
-    protected $step;
40
-
41
-
42
-    /**
43
-     * EE_Number_Input_Display_Strategy constructor.
44
-     * Null is the default value for the incoming arguments because 0 is a valid value.  So we use null
45
-     * to indicate NOT setting this attribute.
46
-     *
47
-     * @param int|null $min
48
-     * @param int|null $max
49
-     * @param int|null $step
50
-     * @throws InvalidArgumentException
51
-     */
52
-    public function __construct($min = null, $max = null, $step = null)
53
-    {
54
-        $this->min = is_numeric($min) || $min === null
55
-            ? $min
56
-            : $this->throwValidationException('min', $min);
57
-        $this->max = is_numeric($max) || $max === null
58
-            ? $max
59
-            : $this->throwValidationException('max', $max);
60
-        $step = $step === 'any' ? 1 : $step;
61
-        $this->step = is_numeric($step) || $step === null
62
-            ? $step
63
-            : $this->throwValidationException('step', $step);
64
-    }
65
-
66
-
67
-    private function throwValidationException($argument_label, $argument_value)
68
-    {
69
-        throw new InvalidArgumentException(
70
-            sprintf(
71
-                esc_html__(
72
-                    'The %1$s parameter value for %2$s must be numeric or null, %3$s was passed into the constructor.',
73
-                    'event_espresso'
74
-                ),
75
-                $argument_label,
76
-                __CLASS__,
77
-                $argument_value
78
-            )
79
-        );
80
-    }
81
-
82
-
83
-
84
-    /**
85
-     * @return string of html to display the field
86
-     */
87
-    public function display()
88
-    {
89
-        $input = $this->_opening_tag('input');
90
-        $input .= $this->_attributes_string(
91
-            array_merge(
92
-                $this->_standard_attributes_array(),
93
-                $this->getNumberInputAttributes()
94
-            )
95
-        );
96
-        $input .= $this->_close_tag();
97
-        return $input;
98
-    }
99
-
100
-
101
-    /**
102
-     * Return the attributes specific to this display strategy
103
-     * @return array
104
-     */
105
-    private function getNumberInputAttributes()
106
-    {
107
-        $attributes = array(
108
-            'type' => 'number',
109
-            'value' => $this->_input->raw_value_in_form()
110
-        );
111
-        if ($this->min !== null) {
112
-            $attributes['min'] = $this->min;
113
-        }
114
-        if ($this->max !== null) {
115
-            $attributes['max'] = $this->max;
116
-        }
117
-        if ($this->step !== null) {
118
-            $attributes['step'] = $this->step;
119
-        }
120
-        return $attributes;
121
-    }
17
+	/**
18
+	 * minimum value for number field
19
+	 *
20
+	 * @var int|null $min
21
+	 */
22
+	protected $min;
23
+
24
+	/**
25
+	 * maximum value for number field
26
+	 *
27
+	 * @var int|null $max
28
+	 */
29
+	protected $max;
30
+
31
+
32
+	/**
33
+	 * This is used to set the "step" attribute for the html5 number input.
34
+	 * Controls the increments on the input when incrementing or decrementing the value.
35
+	 * Note:  Although the step attribute allows for the string "any" to be used, Firefox and Chrome will interpret that
36
+	 * to increment by 1.  So although "any" is accepted as a value, it is converted to 1.
37
+	 * @var float
38
+	 */
39
+	protected $step;
40
+
41
+
42
+	/**
43
+	 * EE_Number_Input_Display_Strategy constructor.
44
+	 * Null is the default value for the incoming arguments because 0 is a valid value.  So we use null
45
+	 * to indicate NOT setting this attribute.
46
+	 *
47
+	 * @param int|null $min
48
+	 * @param int|null $max
49
+	 * @param int|null $step
50
+	 * @throws InvalidArgumentException
51
+	 */
52
+	public function __construct($min = null, $max = null, $step = null)
53
+	{
54
+		$this->min = is_numeric($min) || $min === null
55
+			? $min
56
+			: $this->throwValidationException('min', $min);
57
+		$this->max = is_numeric($max) || $max === null
58
+			? $max
59
+			: $this->throwValidationException('max', $max);
60
+		$step = $step === 'any' ? 1 : $step;
61
+		$this->step = is_numeric($step) || $step === null
62
+			? $step
63
+			: $this->throwValidationException('step', $step);
64
+	}
65
+
66
+
67
+	private function throwValidationException($argument_label, $argument_value)
68
+	{
69
+		throw new InvalidArgumentException(
70
+			sprintf(
71
+				esc_html__(
72
+					'The %1$s parameter value for %2$s must be numeric or null, %3$s was passed into the constructor.',
73
+					'event_espresso'
74
+				),
75
+				$argument_label,
76
+				__CLASS__,
77
+				$argument_value
78
+			)
79
+		);
80
+	}
81
+
82
+
83
+
84
+	/**
85
+	 * @return string of html to display the field
86
+	 */
87
+	public function display()
88
+	{
89
+		$input = $this->_opening_tag('input');
90
+		$input .= $this->_attributes_string(
91
+			array_merge(
92
+				$this->_standard_attributes_array(),
93
+				$this->getNumberInputAttributes()
94
+			)
95
+		);
96
+		$input .= $this->_close_tag();
97
+		return $input;
98
+	}
99
+
100
+
101
+	/**
102
+	 * Return the attributes specific to this display strategy
103
+	 * @return array
104
+	 */
105
+	private function getNumberInputAttributes()
106
+	{
107
+		$attributes = array(
108
+			'type' => 'number',
109
+			'value' => $this->_input->raw_value_in_form()
110
+		);
111
+		if ($this->min !== null) {
112
+			$attributes['min'] = $this->min;
113
+		}
114
+		if ($this->max !== null) {
115
+			$attributes['max'] = $this->max;
116
+		}
117
+		if ($this->step !== null) {
118
+			$attributes['step'] = $this->step;
119
+		}
120
+		return $attributes;
121
+	}
122 122
 
123 123
 }
124 124
 // End of file EE_Number_Input_Display_Strategy.php
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Float_Input.input.php 1 patch
Indentation   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -11,33 +11,33 @@
 block discarded – undo
11 11
 class EE_Float_Input extends EE_Form_Input_Base
12 12
 {
13 13
 
14
-    /**
15
-     * @param array $input_settings
16
-     * @throws InvalidArgumentException
17
-     */
18
-    public function __construct($input_settings = array())
19
-    {
20
-        $this->_set_display_strategy(
21
-            new EE_Number_Input_Display_Strategy(
22
-                isset($input_settings['min_value'])
23
-                    ? $input_settings['min_value']
24
-                    : null,
25
-                isset($input_settings['max_value'])
26
-                    ? $input_settings['max_value']
27
-                    : null,
28
-                isset($input_settings['step_value'])
29
-                    ? $input_settings['step_value']
30
-                    : null
31
-            )
32
-        );
33
-        $this->_set_normalization_strategy(new EE_Float_Normalization());
34
-        $this->_add_validation_strategy(
35
-            new EE_Float_Validation_Strategy(
36
-                isset($input_settings['validation_error_message'])
37
-                    ? $input_settings['validation_error_message']
38
-                    : null
39
-            )
40
-        );
41
-        parent::__construct($input_settings);
42
-    }
14
+	/**
15
+	 * @param array $input_settings
16
+	 * @throws InvalidArgumentException
17
+	 */
18
+	public function __construct($input_settings = array())
19
+	{
20
+		$this->_set_display_strategy(
21
+			new EE_Number_Input_Display_Strategy(
22
+				isset($input_settings['min_value'])
23
+					? $input_settings['min_value']
24
+					: null,
25
+				isset($input_settings['max_value'])
26
+					? $input_settings['max_value']
27
+					: null,
28
+				isset($input_settings['step_value'])
29
+					? $input_settings['step_value']
30
+					: null
31
+			)
32
+		);
33
+		$this->_set_normalization_strategy(new EE_Float_Normalization());
34
+		$this->_add_validation_strategy(
35
+			new EE_Float_Validation_Strategy(
36
+				isset($input_settings['validation_error_message'])
37
+					? $input_settings['validation_error_message']
38
+					: null
39
+			)
40
+		);
41
+		parent::__construct($input_settings);
42
+	}
43 43
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 1 patch
Indentation   +2689 added lines, -2689 removed lines patch added patch discarded remove patch
@@ -15,2696 +15,2696 @@
 block discarded – undo
15 15
 class Events_Admin_Page extends EE_Admin_Page_CPT
16 16
 {
17 17
 
18
-    /**
19
-     * This will hold the event object for event_details screen.
20
-     *
21
-     * @access protected
22
-     * @var EE_Event $_event
23
-     */
24
-    protected $_event;
25
-
26
-
27
-    /**
28
-     * This will hold the category object for category_details screen.
29
-     *
30
-     * @var stdClass $_category
31
-     */
32
-    protected $_category;
33
-
34
-
35
-    /**
36
-     * This will hold the event model instance
37
-     *
38
-     * @var EEM_Event $_event_model
39
-     */
40
-    protected $_event_model;
41
-
42
-
43
-
44
-    /**
45
-     * @var EE_Event
46
-     */
47
-    protected $_cpt_model_obj = false;
48
-
49
-
50
-    /**
51
-     * Initialize page props for this admin page group.
52
-     */
53
-    protected function _init_page_props()
54
-    {
55
-        $this->page_slug = EVENTS_PG_SLUG;
56
-        $this->page_label = EVENTS_LABEL;
57
-        $this->_admin_base_url = EVENTS_ADMIN_URL;
58
-        $this->_admin_base_path = EVENTS_ADMIN;
59
-        $this->_cpt_model_names = array(
60
-            'create_new' => 'EEM_Event',
61
-            'edit'       => 'EEM_Event',
62
-        );
63
-        $this->_cpt_edit_routes = array(
64
-            'espresso_events' => 'edit',
65
-        );
66
-        add_action(
67
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
68
-            array($this, 'verify_event_edit'), 10, 2
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     * Sets the ajax hooks used for this admin page group.
75
-     */
76
-    protected function _ajax_hooks()
77
-    {
78
-        add_action('wp_ajax_ee_save_timezone_setting', array($this, 'save_timezonestring_setting'));
79
-    }
80
-
81
-
82
-    /**
83
-     * Sets the page properties for this admin page group.
84
-     */
85
-    protected function _define_page_props()
86
-    {
87
-        $this->_admin_page_title = EVENTS_LABEL;
88
-        $this->_labels = array(
89
-            'buttons'      => array(
90
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
91
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
92
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
93
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
94
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
95
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
96
-            ),
97
-            'editor_title' => array(
98
-                'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
99
-            ),
100
-            'publishbox'   => array(
101
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
102
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
103
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
104
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
105
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
106
-            ),
107
-        );
108
-    }
109
-
110
-
111
-    /**
112
-     * Sets the page routes property for this admin page group.
113
-     */
114
-    protected function _set_page_routes()
115
-    {
116
-        //load formatter helper
117
-        //load field generator helper
118
-        //is there a evt_id in the request?
119
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
120
-            ? $this->_req_data['EVT_ID']
121
-            : 0;
122
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
123
-        $this->_page_routes = array(
124
-            'default'                       => array(
125
-                'func'       => '_events_overview_list_table',
126
-                'capability' => 'ee_read_events',
127
-            ),
128
-            'create_new'                    => array(
129
-                'func'       => '_create_new_cpt_item',
130
-                'capability' => 'ee_edit_events',
131
-            ),
132
-            'edit'                          => array(
133
-                'func'       => '_edit_cpt_item',
134
-                'capability' => 'ee_edit_event',
135
-                'obj_id'     => $evt_id,
136
-            ),
137
-            'copy_event'                    => array(
138
-                'func'       => '_copy_events',
139
-                'capability' => 'ee_edit_event',
140
-                'obj_id'     => $evt_id,
141
-                'noheader'   => true,
142
-            ),
143
-            'trash_event'                   => array(
144
-                'func'       => '_trash_or_restore_event',
145
-                'args'       => array('event_status' => 'trash'),
146
-                'capability' => 'ee_delete_event',
147
-                'obj_id'     => $evt_id,
148
-                'noheader'   => true,
149
-            ),
150
-            'trash_events'                  => array(
151
-                'func'       => '_trash_or_restore_events',
152
-                'args'       => array('event_status' => 'trash'),
153
-                'capability' => 'ee_delete_events',
154
-                'noheader'   => true,
155
-            ),
156
-            'restore_event'                 => array(
157
-                'func'       => '_trash_or_restore_event',
158
-                'args'       => array('event_status' => 'draft'),
159
-                'capability' => 'ee_delete_event',
160
-                'obj_id'     => $evt_id,
161
-                'noheader'   => true,
162
-            ),
163
-            'restore_events'                => array(
164
-                'func'       => '_trash_or_restore_events',
165
-                'args'       => array('event_status' => 'draft'),
166
-                'capability' => 'ee_delete_events',
167
-                'noheader'   => true,
168
-            ),
169
-            'delete_event'                  => array(
170
-                'func'       => '_delete_event',
171
-                'capability' => 'ee_delete_event',
172
-                'obj_id'     => $evt_id,
173
-                'noheader'   => true,
174
-            ),
175
-            'delete_events'                 => array(
176
-                'func'       => '_delete_events',
177
-                'capability' => 'ee_delete_events',
178
-                'noheader'   => true,
179
-            ),
180
-            'view_report'                   => array(
181
-                'func'      => '_view_report',
182
-                'capablity' => 'ee_edit_events',
183
-            ),
184
-            'default_event_settings'        => array(
185
-                'func'       => '_default_event_settings',
186
-                'capability' => 'manage_options',
187
-            ),
188
-            'update_default_event_settings' => array(
189
-                'func'       => '_update_default_event_settings',
190
-                'capability' => 'manage_options',
191
-                'noheader'   => true,
192
-            ),
193
-            'template_settings'             => array(
194
-                'func'       => '_template_settings',
195
-                'capability' => 'manage_options',
196
-            ),
197
-            //event category tab related
198
-            'add_category'                  => array(
199
-                'func'       => '_category_details',
200
-                'capability' => 'ee_edit_event_category',
201
-                'args'       => array('add'),
202
-            ),
203
-            'edit_category'                 => array(
204
-                'func'       => '_category_details',
205
-                'capability' => 'ee_edit_event_category',
206
-                'args'       => array('edit'),
207
-            ),
208
-            'delete_categories'             => array(
209
-                'func'       => '_delete_categories',
210
-                'capability' => 'ee_delete_event_category',
211
-                'noheader'   => true,
212
-            ),
213
-            'delete_category'               => array(
214
-                'func'       => '_delete_categories',
215
-                'capability' => 'ee_delete_event_category',
216
-                'noheader'   => true,
217
-            ),
218
-            'insert_category'               => array(
219
-                'func'       => '_insert_or_update_category',
220
-                'args'       => array('new_category' => true),
221
-                'capability' => 'ee_edit_event_category',
222
-                'noheader'   => true,
223
-            ),
224
-            'update_category'               => array(
225
-                'func'       => '_insert_or_update_category',
226
-                'args'       => array('new_category' => false),
227
-                'capability' => 'ee_edit_event_category',
228
-                'noheader'   => true,
229
-            ),
230
-            'category_list'                 => array(
231
-                'func'       => '_category_list_table',
232
-                'capability' => 'ee_manage_event_categories',
233
-            ),
234
-        );
235
-    }
236
-
237
-
238
-    /**
239
-     * Set the _page_config property for this admin page group.
240
-     */
241
-    protected function _set_page_config()
242
-    {
243
-        $this->_page_config = array(
244
-            'default'                => array(
245
-                'nav'           => array(
246
-                    'label' => esc_html__('Overview', 'event_espresso'),
247
-                    'order' => 10,
248
-                ),
249
-                'list_table'    => 'Events_Admin_List_Table',
250
-                'help_tabs'     => array(
251
-                    'events_overview_help_tab'                       => array(
252
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
253
-                        'filename' => 'events_overview',
254
-                    ),
255
-                    'events_overview_table_column_headings_help_tab' => array(
256
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
257
-                        'filename' => 'events_overview_table_column_headings',
258
-                    ),
259
-                    'events_overview_filters_help_tab'               => array(
260
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
261
-                        'filename' => 'events_overview_filters',
262
-                    ),
263
-                    'events_overview_view_help_tab'                  => array(
264
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
265
-                        'filename' => 'events_overview_views',
266
-                    ),
267
-                    'events_overview_other_help_tab'                 => array(
268
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
269
-                        'filename' => 'events_overview_other',
270
-                    ),
271
-                ),
272
-                'help_tour'     => array(
273
-                    'Event_Overview_Help_Tour',
274
-                    //'New_Features_Test_Help_Tour' for testing multiple help tour
275
-                ),
276
-                'qtips'         => array(
277
-                    'EE_Event_List_Table_Tips',
278
-                ),
279
-                'require_nonce' => false,
280
-            ),
281
-            'create_new'             => array(
282
-                'nav'           => array(
283
-                    'label'      => esc_html__('Add Event', 'event_espresso'),
284
-                    'order'      => 5,
285
-                    'persistent' => false,
286
-                ),
287
-                'metaboxes'     => array('_register_event_editor_meta_boxes'),
288
-                'help_tabs'     => array(
289
-                    'event_editor_help_tab'                            => array(
290
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
291
-                        'filename' => 'event_editor',
292
-                    ),
293
-                    'event_editor_title_richtexteditor_help_tab'       => array(
294
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
295
-                        'filename' => 'event_editor_title_richtexteditor',
296
-                    ),
297
-                    'event_editor_venue_details_help_tab'              => array(
298
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
299
-                        'filename' => 'event_editor_venue_details',
300
-                    ),
301
-                    'event_editor_event_datetimes_help_tab'            => array(
302
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
303
-                        'filename' => 'event_editor_event_datetimes',
304
-                    ),
305
-                    'event_editor_event_tickets_help_tab'              => array(
306
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
307
-                        'filename' => 'event_editor_event_tickets',
308
-                    ),
309
-                    'event_editor_event_registration_options_help_tab' => array(
310
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
311
-                        'filename' => 'event_editor_event_registration_options',
312
-                    ),
313
-                    'event_editor_tags_categories_help_tab'            => array(
314
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
315
-                        'filename' => 'event_editor_tags_categories',
316
-                    ),
317
-                    'event_editor_questions_registrants_help_tab'      => array(
318
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
319
-                        'filename' => 'event_editor_questions_registrants',
320
-                    ),
321
-                    'event_editor_save_new_event_help_tab'             => array(
322
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
323
-                        'filename' => 'event_editor_save_new_event',
324
-                    ),
325
-                    'event_editor_other_help_tab'                      => array(
326
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
327
-                        'filename' => 'event_editor_other',
328
-                    ),
329
-                ),
330
-                'help_tour'     => array(
331
-                    'Event_Editor_Help_Tour',
332
-                ),
333
-                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
334
-                'require_nonce' => false,
335
-            ),
336
-            'edit'                   => array(
337
-                'nav'           => array(
338
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
339
-                    'order'      => 5,
340
-                    'persistent' => false,
341
-                    'url'        => isset($this->_req_data['post'])
342
-                        ? EE_Admin_Page::add_query_args_and_nonce(
343
-                            array('post' => $this->_req_data['post'], 'action' => 'edit'),
344
-                            $this->_current_page_view_url
345
-                        )
346
-                        : $this->_admin_base_url,
347
-                ),
348
-                'metaboxes'     => array('_register_event_editor_meta_boxes'),
349
-                'help_tabs'     => array(
350
-                    'event_editor_help_tab'                            => array(
351
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
352
-                        'filename' => 'event_editor',
353
-                    ),
354
-                    'event_editor_title_richtexteditor_help_tab'       => array(
355
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
356
-                        'filename' => 'event_editor_title_richtexteditor',
357
-                    ),
358
-                    'event_editor_venue_details_help_tab'              => array(
359
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
360
-                        'filename' => 'event_editor_venue_details',
361
-                    ),
362
-                    'event_editor_event_datetimes_help_tab'            => array(
363
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
364
-                        'filename' => 'event_editor_event_datetimes',
365
-                    ),
366
-                    'event_editor_event_tickets_help_tab'              => array(
367
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
368
-                        'filename' => 'event_editor_event_tickets',
369
-                    ),
370
-                    'event_editor_event_registration_options_help_tab' => array(
371
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
372
-                        'filename' => 'event_editor_event_registration_options',
373
-                    ),
374
-                    'event_editor_tags_categories_help_tab'            => array(
375
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
376
-                        'filename' => 'event_editor_tags_categories',
377
-                    ),
378
-                    'event_editor_questions_registrants_help_tab'      => array(
379
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
380
-                        'filename' => 'event_editor_questions_registrants',
381
-                    ),
382
-                    'event_editor_save_new_event_help_tab'             => array(
383
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
384
-                        'filename' => 'event_editor_save_new_event',
385
-                    ),
386
-                    'event_editor_other_help_tab'                      => array(
387
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
388
-                        'filename' => 'event_editor_other',
389
-                    ),
390
-                ),
391
-                /*'help_tour' => array(
18
+	/**
19
+	 * This will hold the event object for event_details screen.
20
+	 *
21
+	 * @access protected
22
+	 * @var EE_Event $_event
23
+	 */
24
+	protected $_event;
25
+
26
+
27
+	/**
28
+	 * This will hold the category object for category_details screen.
29
+	 *
30
+	 * @var stdClass $_category
31
+	 */
32
+	protected $_category;
33
+
34
+
35
+	/**
36
+	 * This will hold the event model instance
37
+	 *
38
+	 * @var EEM_Event $_event_model
39
+	 */
40
+	protected $_event_model;
41
+
42
+
43
+
44
+	/**
45
+	 * @var EE_Event
46
+	 */
47
+	protected $_cpt_model_obj = false;
48
+
49
+
50
+	/**
51
+	 * Initialize page props for this admin page group.
52
+	 */
53
+	protected function _init_page_props()
54
+	{
55
+		$this->page_slug = EVENTS_PG_SLUG;
56
+		$this->page_label = EVENTS_LABEL;
57
+		$this->_admin_base_url = EVENTS_ADMIN_URL;
58
+		$this->_admin_base_path = EVENTS_ADMIN;
59
+		$this->_cpt_model_names = array(
60
+			'create_new' => 'EEM_Event',
61
+			'edit'       => 'EEM_Event',
62
+		);
63
+		$this->_cpt_edit_routes = array(
64
+			'espresso_events' => 'edit',
65
+		);
66
+		add_action(
67
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
68
+			array($this, 'verify_event_edit'), 10, 2
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 * Sets the ajax hooks used for this admin page group.
75
+	 */
76
+	protected function _ajax_hooks()
77
+	{
78
+		add_action('wp_ajax_ee_save_timezone_setting', array($this, 'save_timezonestring_setting'));
79
+	}
80
+
81
+
82
+	/**
83
+	 * Sets the page properties for this admin page group.
84
+	 */
85
+	protected function _define_page_props()
86
+	{
87
+		$this->_admin_page_title = EVENTS_LABEL;
88
+		$this->_labels = array(
89
+			'buttons'      => array(
90
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
91
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
92
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
93
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
94
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
95
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
96
+			),
97
+			'editor_title' => array(
98
+				'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
99
+			),
100
+			'publishbox'   => array(
101
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
102
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
103
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
104
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
105
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
106
+			),
107
+		);
108
+	}
109
+
110
+
111
+	/**
112
+	 * Sets the page routes property for this admin page group.
113
+	 */
114
+	protected function _set_page_routes()
115
+	{
116
+		//load formatter helper
117
+		//load field generator helper
118
+		//is there a evt_id in the request?
119
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
120
+			? $this->_req_data['EVT_ID']
121
+			: 0;
122
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
123
+		$this->_page_routes = array(
124
+			'default'                       => array(
125
+				'func'       => '_events_overview_list_table',
126
+				'capability' => 'ee_read_events',
127
+			),
128
+			'create_new'                    => array(
129
+				'func'       => '_create_new_cpt_item',
130
+				'capability' => 'ee_edit_events',
131
+			),
132
+			'edit'                          => array(
133
+				'func'       => '_edit_cpt_item',
134
+				'capability' => 'ee_edit_event',
135
+				'obj_id'     => $evt_id,
136
+			),
137
+			'copy_event'                    => array(
138
+				'func'       => '_copy_events',
139
+				'capability' => 'ee_edit_event',
140
+				'obj_id'     => $evt_id,
141
+				'noheader'   => true,
142
+			),
143
+			'trash_event'                   => array(
144
+				'func'       => '_trash_or_restore_event',
145
+				'args'       => array('event_status' => 'trash'),
146
+				'capability' => 'ee_delete_event',
147
+				'obj_id'     => $evt_id,
148
+				'noheader'   => true,
149
+			),
150
+			'trash_events'                  => array(
151
+				'func'       => '_trash_or_restore_events',
152
+				'args'       => array('event_status' => 'trash'),
153
+				'capability' => 'ee_delete_events',
154
+				'noheader'   => true,
155
+			),
156
+			'restore_event'                 => array(
157
+				'func'       => '_trash_or_restore_event',
158
+				'args'       => array('event_status' => 'draft'),
159
+				'capability' => 'ee_delete_event',
160
+				'obj_id'     => $evt_id,
161
+				'noheader'   => true,
162
+			),
163
+			'restore_events'                => array(
164
+				'func'       => '_trash_or_restore_events',
165
+				'args'       => array('event_status' => 'draft'),
166
+				'capability' => 'ee_delete_events',
167
+				'noheader'   => true,
168
+			),
169
+			'delete_event'                  => array(
170
+				'func'       => '_delete_event',
171
+				'capability' => 'ee_delete_event',
172
+				'obj_id'     => $evt_id,
173
+				'noheader'   => true,
174
+			),
175
+			'delete_events'                 => array(
176
+				'func'       => '_delete_events',
177
+				'capability' => 'ee_delete_events',
178
+				'noheader'   => true,
179
+			),
180
+			'view_report'                   => array(
181
+				'func'      => '_view_report',
182
+				'capablity' => 'ee_edit_events',
183
+			),
184
+			'default_event_settings'        => array(
185
+				'func'       => '_default_event_settings',
186
+				'capability' => 'manage_options',
187
+			),
188
+			'update_default_event_settings' => array(
189
+				'func'       => '_update_default_event_settings',
190
+				'capability' => 'manage_options',
191
+				'noheader'   => true,
192
+			),
193
+			'template_settings'             => array(
194
+				'func'       => '_template_settings',
195
+				'capability' => 'manage_options',
196
+			),
197
+			//event category tab related
198
+			'add_category'                  => array(
199
+				'func'       => '_category_details',
200
+				'capability' => 'ee_edit_event_category',
201
+				'args'       => array('add'),
202
+			),
203
+			'edit_category'                 => array(
204
+				'func'       => '_category_details',
205
+				'capability' => 'ee_edit_event_category',
206
+				'args'       => array('edit'),
207
+			),
208
+			'delete_categories'             => array(
209
+				'func'       => '_delete_categories',
210
+				'capability' => 'ee_delete_event_category',
211
+				'noheader'   => true,
212
+			),
213
+			'delete_category'               => array(
214
+				'func'       => '_delete_categories',
215
+				'capability' => 'ee_delete_event_category',
216
+				'noheader'   => true,
217
+			),
218
+			'insert_category'               => array(
219
+				'func'       => '_insert_or_update_category',
220
+				'args'       => array('new_category' => true),
221
+				'capability' => 'ee_edit_event_category',
222
+				'noheader'   => true,
223
+			),
224
+			'update_category'               => array(
225
+				'func'       => '_insert_or_update_category',
226
+				'args'       => array('new_category' => false),
227
+				'capability' => 'ee_edit_event_category',
228
+				'noheader'   => true,
229
+			),
230
+			'category_list'                 => array(
231
+				'func'       => '_category_list_table',
232
+				'capability' => 'ee_manage_event_categories',
233
+			),
234
+		);
235
+	}
236
+
237
+
238
+	/**
239
+	 * Set the _page_config property for this admin page group.
240
+	 */
241
+	protected function _set_page_config()
242
+	{
243
+		$this->_page_config = array(
244
+			'default'                => array(
245
+				'nav'           => array(
246
+					'label' => esc_html__('Overview', 'event_espresso'),
247
+					'order' => 10,
248
+				),
249
+				'list_table'    => 'Events_Admin_List_Table',
250
+				'help_tabs'     => array(
251
+					'events_overview_help_tab'                       => array(
252
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
253
+						'filename' => 'events_overview',
254
+					),
255
+					'events_overview_table_column_headings_help_tab' => array(
256
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
257
+						'filename' => 'events_overview_table_column_headings',
258
+					),
259
+					'events_overview_filters_help_tab'               => array(
260
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
261
+						'filename' => 'events_overview_filters',
262
+					),
263
+					'events_overview_view_help_tab'                  => array(
264
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
265
+						'filename' => 'events_overview_views',
266
+					),
267
+					'events_overview_other_help_tab'                 => array(
268
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
269
+						'filename' => 'events_overview_other',
270
+					),
271
+				),
272
+				'help_tour'     => array(
273
+					'Event_Overview_Help_Tour',
274
+					//'New_Features_Test_Help_Tour' for testing multiple help tour
275
+				),
276
+				'qtips'         => array(
277
+					'EE_Event_List_Table_Tips',
278
+				),
279
+				'require_nonce' => false,
280
+			),
281
+			'create_new'             => array(
282
+				'nav'           => array(
283
+					'label'      => esc_html__('Add Event', 'event_espresso'),
284
+					'order'      => 5,
285
+					'persistent' => false,
286
+				),
287
+				'metaboxes'     => array('_register_event_editor_meta_boxes'),
288
+				'help_tabs'     => array(
289
+					'event_editor_help_tab'                            => array(
290
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
291
+						'filename' => 'event_editor',
292
+					),
293
+					'event_editor_title_richtexteditor_help_tab'       => array(
294
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
295
+						'filename' => 'event_editor_title_richtexteditor',
296
+					),
297
+					'event_editor_venue_details_help_tab'              => array(
298
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
299
+						'filename' => 'event_editor_venue_details',
300
+					),
301
+					'event_editor_event_datetimes_help_tab'            => array(
302
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
303
+						'filename' => 'event_editor_event_datetimes',
304
+					),
305
+					'event_editor_event_tickets_help_tab'              => array(
306
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
307
+						'filename' => 'event_editor_event_tickets',
308
+					),
309
+					'event_editor_event_registration_options_help_tab' => array(
310
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
311
+						'filename' => 'event_editor_event_registration_options',
312
+					),
313
+					'event_editor_tags_categories_help_tab'            => array(
314
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
315
+						'filename' => 'event_editor_tags_categories',
316
+					),
317
+					'event_editor_questions_registrants_help_tab'      => array(
318
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
319
+						'filename' => 'event_editor_questions_registrants',
320
+					),
321
+					'event_editor_save_new_event_help_tab'             => array(
322
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
323
+						'filename' => 'event_editor_save_new_event',
324
+					),
325
+					'event_editor_other_help_tab'                      => array(
326
+						'title'    => esc_html__('Event Other', 'event_espresso'),
327
+						'filename' => 'event_editor_other',
328
+					),
329
+				),
330
+				'help_tour'     => array(
331
+					'Event_Editor_Help_Tour',
332
+				),
333
+				'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
334
+				'require_nonce' => false,
335
+			),
336
+			'edit'                   => array(
337
+				'nav'           => array(
338
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
339
+					'order'      => 5,
340
+					'persistent' => false,
341
+					'url'        => isset($this->_req_data['post'])
342
+						? EE_Admin_Page::add_query_args_and_nonce(
343
+							array('post' => $this->_req_data['post'], 'action' => 'edit'),
344
+							$this->_current_page_view_url
345
+						)
346
+						: $this->_admin_base_url,
347
+				),
348
+				'metaboxes'     => array('_register_event_editor_meta_boxes'),
349
+				'help_tabs'     => array(
350
+					'event_editor_help_tab'                            => array(
351
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
352
+						'filename' => 'event_editor',
353
+					),
354
+					'event_editor_title_richtexteditor_help_tab'       => array(
355
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
356
+						'filename' => 'event_editor_title_richtexteditor',
357
+					),
358
+					'event_editor_venue_details_help_tab'              => array(
359
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
360
+						'filename' => 'event_editor_venue_details',
361
+					),
362
+					'event_editor_event_datetimes_help_tab'            => array(
363
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
364
+						'filename' => 'event_editor_event_datetimes',
365
+					),
366
+					'event_editor_event_tickets_help_tab'              => array(
367
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
368
+						'filename' => 'event_editor_event_tickets',
369
+					),
370
+					'event_editor_event_registration_options_help_tab' => array(
371
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
372
+						'filename' => 'event_editor_event_registration_options',
373
+					),
374
+					'event_editor_tags_categories_help_tab'            => array(
375
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
376
+						'filename' => 'event_editor_tags_categories',
377
+					),
378
+					'event_editor_questions_registrants_help_tab'      => array(
379
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
380
+						'filename' => 'event_editor_questions_registrants',
381
+					),
382
+					'event_editor_save_new_event_help_tab'             => array(
383
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
384
+						'filename' => 'event_editor_save_new_event',
385
+					),
386
+					'event_editor_other_help_tab'                      => array(
387
+						'title'    => esc_html__('Event Other', 'event_espresso'),
388
+						'filename' => 'event_editor_other',
389
+					),
390
+				),
391
+				/*'help_tour' => array(
392 392
 					'Event_Edit_Help_Tour'
393 393
 				),*/
394
-                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
395
-                'require_nonce' => false,
396
-            ),
397
-            'default_event_settings' => array(
398
-                'nav'           => array(
399
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
400
-                    'order' => 40,
401
-                ),
402
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
403
-                'labels'        => array(
404
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
405
-                ),
406
-                'help_tabs'     => array(
407
-                    'default_settings_help_tab'        => array(
408
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
409
-                        'filename' => 'events_default_settings',
410
-                    ),
411
-                    'default_settings_status_help_tab' => array(
412
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
413
-                        'filename' => 'events_default_settings_status',
414
-                    ),
415
-                    'default_maximum_tickets_help_tab' => array(
416
-                        'title' => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
417
-                        'filename' => 'events_default_settings_max_tickets',
418
-                    )
419
-                ),
420
-                'help_tour'     => array('Event_Default_Settings_Help_Tour'),
421
-                'require_nonce' => false,
422
-            ),
423
-            //template settings
424
-            'template_settings'      => array(
425
-                'nav'           => array(
426
-                    'label' => esc_html__('Templates', 'event_espresso'),
427
-                    'order' => 30,
428
-                ),
429
-                'metaboxes'     => $this->_default_espresso_metaboxes,
430
-                'help_tabs'     => array(
431
-                    'general_settings_templates_help_tab' => array(
432
-                        'title'    => esc_html__('Templates', 'event_espresso'),
433
-                        'filename' => 'general_settings_templates',
434
-                    ),
435
-                ),
436
-                'help_tour'     => array('Templates_Help_Tour'),
437
-                'require_nonce' => false,
438
-            ),
439
-            //event category stuff
440
-            'add_category'           => array(
441
-                'nav'           => array(
442
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
443
-                    'order'      => 15,
444
-                    'persistent' => false,
445
-                ),
446
-                'help_tabs'     => array(
447
-                    'add_category_help_tab' => array(
448
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
449
-                        'filename' => 'events_add_category',
450
-                    ),
451
-                ),
452
-                'help_tour'     => array('Event_Add_Category_Help_Tour'),
453
-                'metaboxes'     => array('_publish_post_box'),
454
-                'require_nonce' => false,
455
-            ),
456
-            'edit_category'          => array(
457
-                'nav'           => array(
458
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
459
-                    'order'      => 15,
460
-                    'persistent' => false,
461
-                    'url'        => isset($this->_req_data['EVT_CAT_ID'])
462
-                        ? add_query_arg(
463
-                            array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID']),
464
-                            $this->_current_page_view_url
465
-                        )
466
-                        : $this->_admin_base_url,
467
-                ),
468
-                'help_tabs'     => array(
469
-                    'edit_category_help_tab' => array(
470
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
471
-                        'filename' => 'events_edit_category',
472
-                    ),
473
-                ),
474
-                /*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
475
-                'metaboxes'     => array('_publish_post_box'),
476
-                'require_nonce' => false,
477
-            ),
478
-            'category_list'          => array(
479
-                'nav'           => array(
480
-                    'label' => esc_html__('Categories', 'event_espresso'),
481
-                    'order' => 20,
482
-                ),
483
-                'list_table'    => 'Event_Categories_Admin_List_Table',
484
-                'help_tabs'     => array(
485
-                    'events_categories_help_tab'                       => array(
486
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
487
-                        'filename' => 'events_categories',
488
-                    ),
489
-                    'events_categories_table_column_headings_help_tab' => array(
490
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
491
-                        'filename' => 'events_categories_table_column_headings',
492
-                    ),
493
-                    'events_categories_view_help_tab'                  => array(
494
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
495
-                        'filename' => 'events_categories_views',
496
-                    ),
497
-                    'events_categories_other_help_tab'                 => array(
498
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
499
-                        'filename' => 'events_categories_other',
500
-                    ),
501
-                ),
502
-                'help_tour'     => array(
503
-                    'Event_Categories_Help_Tour',
504
-                ),
505
-                'metaboxes'     => $this->_default_espresso_metaboxes,
506
-                'require_nonce' => false,
507
-            ),
508
-        );
509
-    }
510
-
511
-
512
-    /**
513
-     * Used to register any global screen options if necessary for every route in this admin page group.
514
-     */
515
-    protected function _add_screen_options()
516
-    {
517
-    }
518
-
519
-
520
-    /**
521
-     * Implementing the screen options for the 'default' route.
522
-     */
523
-    protected function _add_screen_options_default()
524
-    {
525
-        $this->_per_page_screen_option();
526
-    }
527
-
528
-
529
-    /**
530
-     * Implementing screen options for the category list route.
531
-     */
532
-    protected function _add_screen_options_category_list()
533
-    {
534
-        $page_title = $this->_admin_page_title;
535
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
536
-        $this->_per_page_screen_option();
537
-        $this->_admin_page_title = $page_title;
538
-    }
539
-
540
-
541
-    /**
542
-     * Used to register any global feature pointers for the admin page group.
543
-     */
544
-    protected function _add_feature_pointers()
545
-    {
546
-    }
547
-
548
-
549
-    /**
550
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
551
-     */
552
-    public function load_scripts_styles()
553
-    {
554
-        wp_register_style(
555
-            'events-admin-css',
556
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
557
-            array(),
558
-            EVENT_ESPRESSO_VERSION
559
-        );
560
-        wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
561
-        wp_enqueue_style('events-admin-css');
562
-        wp_enqueue_style('ee-cat-admin');
563
-        //todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
564
-        //registers for all views
565
-        //scripts
566
-        wp_register_script(
567
-            'event_editor_js',
568
-            EVENTS_ASSETS_URL . 'event_editor.js',
569
-            array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
570
-            EVENT_ESPRESSO_VERSION,
571
-            true
572
-        );
573
-    }
574
-
575
-
576
-
577
-    /**
578
-     * Enqueuing scripts and styles specific to this view
579
-     */
580
-    public function load_scripts_styles_create_new()
581
-    {
582
-        $this->load_scripts_styles_edit();
583
-    }
584
-
585
-
586
-
587
-    /**
588
-     * Enqueuing scripts and styles specific to this view
589
-     */
590
-    public function load_scripts_styles_edit()
591
-    {
592
-        //styles
593
-        wp_enqueue_style('espresso-ui-theme');
594
-        wp_register_style(
595
-            'event-editor-css',
596
-            EVENTS_ASSETS_URL . 'event-editor.css',
597
-            array('ee-admin-css'),
598
-            EVENT_ESPRESSO_VERSION
599
-        );
600
-        wp_enqueue_style('event-editor-css');
601
-        //scripts
602
-        wp_register_script(
603
-            'event-datetime-metabox',
604
-            EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
605
-            array('event_editor_js', 'ee-datepicker'),
606
-            EVENT_ESPRESSO_VERSION
607
-        );
608
-        wp_enqueue_script('event-datetime-metabox');
609
-    }
610
-
611
-
612
-    /**
613
-     * Populating the _views property for the category list table view.
614
-     */
615
-    protected function _set_list_table_views_category_list()
616
-    {
617
-        $this->_views = array(
618
-            'all' => array(
619
-                'slug'        => 'all',
620
-                'label'       => esc_html__('All', 'event_espresso'),
621
-                'count'       => 0,
622
-                'bulk_action' => array(
623
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
624
-                ),
625
-            ),
626
-        );
627
-    }
628
-
629
-
630
-    /**
631
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
632
-     */
633
-    public function admin_init()
634
-    {
635
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
636
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
637
-            'event_espresso'
638
-        );
639
-    }
640
-
641
-
642
-    /**
643
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page group.
644
-     */
645
-    public function admin_notices()
646
-    {
647
-    }
648
-
649
-
650
-    /**
651
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
652
-     * this admin page group.
653
-     */
654
-    public function admin_footer_scripts()
655
-    {
656
-    }
657
-
658
-
659
-
660
-    /**
661
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
662
-     * warning (via EE_Error::add_error());
663
-     *
664
-     * @param  EE_Event $event Event object
665
-     * @param string    $req_type
666
-     * @return void
667
-     * @throws EE_Error
668
-     * @access public
669
-     */
670
-    public function verify_event_edit($event = null, $req_type = '')
671
-    {
672
-        // don't need to do this when processing
673
-        if(!empty($req_type)) {
674
-            return;
675
-        }
676
-        // no event?
677
-        if (empty($event)) {
678
-            // set event
679
-            $event = $this->_cpt_model_obj;
680
-        }
681
-        // STILL no event?
682
-        if (! $event instanceof EE_Event) {
683
-            return;
684
-        }
685
-        $orig_status = $event->status();
686
-        // first check if event is active.
687
-        if (
688
-            $orig_status === EEM_Event::cancelled
689
-            || $orig_status === EEM_Event::postponed
690
-            || $event->is_expired()
691
-            || $event->is_inactive()
692
-        ) {
693
-            return;
694
-        }
695
-        //made it here so it IS active... next check that any of the tickets are sold.
696
-        if ($event->is_sold_out(true)) {
697
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
698
-                EE_Error::add_attention(
699
-                    sprintf(
700
-                        esc_html__(
701
-                            'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
702
-                            'event_espresso'
703
-                        ),
704
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
705
-                    )
706
-                );
707
-            }
708
-            return;
709
-        } else if ($orig_status === EEM_Event::sold_out) {
710
-            EE_Error::add_attention(
711
-                sprintf(
712
-                    esc_html__(
713
-                        'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
714
-                        'event_espresso'
715
-                    ),
716
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
717
-                )
718
-            );
719
-        }
720
-        //now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
721
-        if ( ! $event->tickets_on_sale()) {
722
-            return;
723
-        }
724
-        //made it here so show warning
725
-        $this->_edit_event_warning();
726
-    }
727
-
728
-
729
-
730
-    /**
731
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
732
-     * When needed, hook this into a EE_Error::add_error() notice.
733
-     *
734
-     * @access protected
735
-     * @return void
736
-     */
737
-    protected function _edit_event_warning()
738
-    {
739
-        // we don't want to add warnings during these requests
740
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'editpost') {
741
-            return;
742
-        }
743
-        EE_Error::add_attention(
744
-            esc_html__(
745
-                'Please be advised that this event has been published and is open for registrations on your website. If you update any registration-related details (i.e. custom questions, messages, tickets, datetimes, etc.) while a registration is in process, the registration process could be interrupted and result in errors for the person registering and potentially incorrect registration or transaction data inside Event Espresso. We recommend editing events during a period of slow traffic, or even temporarily changing the status of an event to "Draft" until your edits are complete.',
746
-                'event_espresso'
747
-            )
748
-        );
749
-    }
750
-
751
-
752
-
753
-    /**
754
-     * When a user is creating a new event, notify them if they haven't set their timezone.
755
-     * Otherwise, do the normal logic
756
-     *
757
-     * @return string
758
-     * @throws \EE_Error
759
-     */
760
-    protected function _create_new_cpt_item()
761
-    {
762
-        $has_timezone_string = get_option('timezone_string');
763
-        //only nag them about setting their timezone if it's their first event, and they haven't already done it
764
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
765
-            EE_Error::add_attention(
766
-                sprintf(
767
-                    __(
768
-                        'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
769
-                        'event_espresso'
770
-                    ),
771
-                    '<br>',
772
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
773
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
774
-                    . '</select>',
775
-                    '<button class="button button-secondary timezone-submit">',
776
-                    '</button><span class="spinner"></span>'
777
-                ),
778
-                __FILE__,
779
-                __FUNCTION__,
780
-                __LINE__
781
-            );
782
-        }
783
-        return parent::_create_new_cpt_item();
784
-    }
785
-
786
-
787
-    /**
788
-     * Sets the _views property for the default route in this admin page group.
789
-     */
790
-    protected function _set_list_table_views_default()
791
-    {
792
-        $this->_views = array(
793
-            'all'   => array(
794
-                'slug'        => 'all',
795
-                'label'       => esc_html__('View All Events', 'event_espresso'),
796
-                'count'       => 0,
797
-                'bulk_action' => array(
798
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
799
-                ),
800
-            ),
801
-            'draft' => array(
802
-                'slug'        => 'draft',
803
-                'label'       => esc_html__('Draft', 'event_espresso'),
804
-                'count'       => 0,
805
-                'bulk_action' => array(
806
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
807
-                ),
808
-            ),
809
-        );
810
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
811
-            $this->_views['trash'] = array(
812
-                'slug'        => 'trash',
813
-                'label'       => esc_html__('Trash', 'event_espresso'),
814
-                'count'       => 0,
815
-                'bulk_action' => array(
816
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
817
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
818
-                ),
819
-            );
820
-        }
821
-    }
822
-
823
-
824
-
825
-    /**
826
-     * Provides the legend item array for the default list table view.
827
-     * @return array
828
-     */
829
-    protected function _event_legend_items()
830
-    {
831
-        $items = array(
832
-            'view_details'   => array(
833
-                'class' => 'dashicons dashicons-search',
834
-                'desc'  => esc_html__('View Event', 'event_espresso'),
835
-            ),
836
-            'edit_event'     => array(
837
-                'class' => 'ee-icon ee-icon-calendar-edit',
838
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
839
-            ),
840
-            'view_attendees' => array(
841
-                'class' => 'dashicons dashicons-groups',
842
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
843
-            ),
844
-        );
845
-        $items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
846
-        $statuses = array(
847
-            'sold_out_status'  => array(
848
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
849
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
850
-            ),
851
-            'active_status'    => array(
852
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
853
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
854
-            ),
855
-            'upcoming_status'  => array(
856
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
857
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
858
-            ),
859
-            'postponed_status' => array(
860
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
861
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
862
-            ),
863
-            'cancelled_status' => array(
864
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
865
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
866
-            ),
867
-            'expired_status'   => array(
868
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
869
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
870
-            ),
871
-            'inactive_status'  => array(
872
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
873
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
874
-            ),
875
-        );
876
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
877
-        return array_merge($items, $statuses);
878
-    }
879
-
880
-
881
-
882
-    /**
883
-     * @return EEM_Event
884
-     */
885
-    private function _event_model()
886
-    {
887
-        if ( ! $this->_event_model instanceof EEM_Event) {
888
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
889
-        }
890
-        return $this->_event_model;
891
-    }
892
-
893
-
894
-
895
-    /**
896
-     * Adds extra buttons to the WP CPT permalink field row.
897
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
898
-     *
899
-     * @param  string $return    the current html
900
-     * @param  int    $id        the post id for the page
901
-     * @param  string $new_title What the title is
902
-     * @param  string $new_slug  what the slug is
903
-     * @return string            The new html string for the permalink area
904
-     */
905
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
906
-    {
907
-        //make sure this is only when editing
908
-        if ( ! empty($id)) {
909
-            $post = get_post($id);
910
-            $return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
911
-                       . esc_html__('Shortcode', 'event_espresso')
912
-                       . '</a> ';
913
-            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
914
-                       . $post->ID
915
-                       . ']">';
916
-        }
917
-        return $return;
918
-    }
919
-
920
-
921
-
922
-    /**
923
-     * _events_overview_list_table
924
-     * This contains the logic for showing the events_overview list
925
-     *
926
-     * @access protected
927
-     * @return void
928
-     * @throws \EE_Error
929
-     */
930
-    protected function _events_overview_list_table()
931
-    {
932
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
933
-        $this->_template_args['after_list_table'] = ! empty($this->_template_args['after_list_table'])
934
-            ? (array)$this->_template_args['after_list_table']
935
-            : array();
936
-        $this->_template_args['after_list_table']['view_event_list_button'] = EEH_HTML::br()
937
-                                                                              . EEH_Template::get_button_or_link(
938
-                get_post_type_archive_link('espresso_events'),
939
-                esc_html__("View Event Archive Page", "event_espresso"),
940
-                'button'
941
-            );
942
-        $this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
943
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
944
-                'create_new',
945
-                'add',
946
-                array(),
947
-                'add-new-h2'
948
-            );
949
-        $this->display_admin_list_table_page_with_no_sidebar();
950
-    }
951
-
952
-
953
-
954
-    /**
955
-     * this allows for extra misc actions in the default WP publish box
956
-     *
957
-     * @return void
958
-     */
959
-    public function extra_misc_actions_publish_box()
960
-    {
961
-        $this->_generate_publish_box_extra_content();
962
-    }
963
-
964
-
965
-
966
-    /**
967
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been saved.
968
-     * Typically you would use this to save any additional data.
969
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
970
-     * ALSO very important.  When a post transitions from scheduled to published,
971
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from other meta saves.
972
-     * So MAKE sure that you handle this accordingly.
973
-     *
974
-     * @access protected
975
-     * @abstract
976
-     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
977
-     * @param  object $post    The post object of the cpt that was saved.
978
-     * @return void
979
-     * @throws \EE_Error
980
-     */
981
-    protected function _insert_update_cpt_item($post_id, $post)
982
-    {
983
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
984
-            //get out we're not processing an event save.
985
-            return;
986
-        }
987
-        $event_values = array(
988
-            'EVT_display_desc'                => ! empty($this->_req_data['display_desc']) ? 1 : 0,
989
-            'EVT_display_ticket_selector'     => ! empty($this->_req_data['display_ticket_selector']) ? 1 : 0,
990
-            'EVT_additional_limit'            => min(
991
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
992
-                ! empty($this->_req_data['additional_limit']) ? $this->_req_data['additional_limit'] : null
993
-            ),
994
-            'EVT_default_registration_status' => ! empty($this->_req_data['EVT_default_registration_status'])
995
-                ? $this->_req_data['EVT_default_registration_status']
996
-                : EE_Registry::instance()->CFG->registration->default_STS_ID,
997
-            'EVT_member_only'                 => ! empty($this->_req_data['member_only']) ? 1 : 0,
998
-            'EVT_allow_overflow'              => ! empty($this->_req_data['EVT_allow_overflow']) ? 1 : 0,
999
-            'EVT_timezone_string'             => ! empty($this->_req_data['timezone_string'])
1000
-                ? $this->_req_data['timezone_string'] : null,
1001
-            'EVT_external_URL'                => ! empty($this->_req_data['externalURL'])
1002
-                ? $this->_req_data['externalURL'] : null,
1003
-            'EVT_phone'                       => ! empty($this->_req_data['event_phone'])
1004
-                ? $this->_req_data['event_phone'] : null,
1005
-        );
1006
-        //update event
1007
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1008
-        //get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
1009
-        $get_one_where = array(
1010
-            $this->_event_model()->primary_key_name() => $post_id,
1011
-            'OR' => array(
1012
-                'status' => $post->post_status,
1013
-                // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1014
-                // but the returned object here has a status of "publish", so use the original post status as well
1015
-                'status*1' => $this->_req_data['original_post_status'],
1016
-            )
1017
-        );
1018
-        $event = $this->_event_model()->get_one(array($get_one_where));
1019
-        //the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
1020
-        $event_update_callbacks = apply_filters(
1021
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1022
-            array(
1023
-                array($this, '_default_venue_update'),
1024
-                array($this, '_default_tickets_update')
1025
-            )
1026
-        );
1027
-        $att_success = true;
1028
-        foreach ($event_update_callbacks as $e_callback) {
1029
-            $_success = is_callable($e_callback)
1030
-                ? call_user_func($e_callback, $event, $this->_req_data)
1031
-                : false;
1032
-            //if ANY of these updates fail then we want the appropriate global error message
1033
-            $att_success = ! $att_success ? $att_success : $_success;
1034
-        }
1035
-        //any errors?
1036
-        if ($success && false === $att_success) {
1037
-            EE_Error::add_error(
1038
-                esc_html__(
1039
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1040
-                    'event_espresso'
1041
-                ),
1042
-                __FILE__,
1043
-                __FUNCTION__,
1044
-                __LINE__
1045
-            );
1046
-        } else if ($success === false) {
1047
-            EE_Error::add_error(
1048
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1049
-                __FILE__,
1050
-                __FUNCTION__,
1051
-                __LINE__
1052
-            );
1053
-        }
1054
-    }
1055
-
1056
-
1057
-
1058
-    /**
1059
-     * @see parent::restore_item()
1060
-     * @param int $post_id
1061
-     * @param int $revision_id
1062
-     */
1063
-    protected function _restore_cpt_item($post_id, $revision_id)
1064
-    {
1065
-        //copy existing event meta to new post
1066
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1067
-        if ($post_evt instanceof EE_Event) {
1068
-            //meta revision restore
1069
-            $post_evt->restore_revision($revision_id);
1070
-            //related objs restore
1071
-            $post_evt->restore_revision($revision_id, array('Venue', 'Datetime', 'Price'));
1072
-        }
1073
-    }
1074
-
1075
-
1076
-
1077
-    /**
1078
-     * Attach the venue to the Event
1079
-     *
1080
-     * @param  \EE_Event $evtobj Event Object to add the venue to
1081
-     * @param  array     $data   The request data from the form
1082
-     * @return bool           Success or fail.
1083
-     */
1084
-    protected function _default_venue_update(\EE_Event $evtobj, $data)
1085
-    {
1086
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1087
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1088
-        $rows_affected = null;
1089
-        $venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1090
-        // very important.  If we don't have a venue name...
1091
-        // then we'll get out because not necessary to create empty venue
1092
-        if (empty($data['venue_title'])) {
1093
-            return false;
1094
-        }
1095
-        $venue_array = array(
1096
-            'VNU_wp_user'         => $evtobj->get('EVT_wp_user'),
1097
-            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1098
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1099
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1100
-            'VNU_short_desc'      => ! empty($data['venue_short_description']) ? $data['venue_short_description']
1101
-                : null,
1102
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1103
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1104
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1105
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1106
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1107
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1108
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1109
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1110
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1111
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1112
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1113
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1114
-            'status'              => 'publish',
1115
-        );
1116
-        //if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1117
-        if ( ! empty($venue_id)) {
1118
-            $update_where = array($venue_model->primary_key_name() => $venue_id);
1119
-            $rows_affected = $venue_model->update($venue_array, array($update_where));
1120
-            //we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
1121
-            $evtobj->_add_relation_to($venue_id, 'Venue');
1122
-            return $rows_affected > 0 ? true : false;
1123
-        } else {
1124
-            //we insert the venue
1125
-            $venue_id = $venue_model->insert($venue_array);
1126
-            $evtobj->_add_relation_to($venue_id, 'Venue');
1127
-            return ! empty($venue_id) ? true : false;
1128
-        }
1129
-        //when we have the ancestor come in it's already been handled by the revision save.
1130
-    }
1131
-
1132
-
1133
-
1134
-    /**
1135
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1136
-     *
1137
-     * @param  EE_Event $evtobj The Event object we're attaching data to
1138
-     * @param  array    $data   The request data from the form
1139
-     * @return array
1140
-     */
1141
-    protected function _default_tickets_update(EE_Event $evtobj, $data)
1142
-    {
1143
-        $success = true;
1144
-        $saved_dtt = null;
1145
-        $saved_tickets = array();
1146
-        $incoming_date_formats = array('Y-m-d', 'h:i a');
1147
-        foreach ($data['edit_event_datetimes'] as $row => $dtt) {
1148
-            //trim all values to ensure any excess whitespace is removed.
1149
-            $dtt = array_map('trim', $dtt);
1150
-            $dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end']
1151
-                : $dtt['DTT_EVT_start'];
1152
-            $datetime_values = array(
1153
-                'DTT_ID'        => ! empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : null,
1154
-                'DTT_EVT_start' => $dtt['DTT_EVT_start'],
1155
-                'DTT_EVT_end'   => $dtt['DTT_EVT_end'],
1156
-                'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'],
1157
-                'DTT_order'     => $row,
1158
-            );
1159
-            //if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1160
-            if ( ! empty($dtt['DTT_ID'])) {
1161
-                $DTM = EE_Registry::instance()
1162
-                                  ->load_model('Datetime', array($evtobj->get_timezone()))
1163
-                                  ->get_one_by_ID($dtt['DTT_ID']);
1164
-                $DTM->set_date_format($incoming_date_formats[0]);
1165
-                $DTM->set_time_format($incoming_date_formats[1]);
1166
-                foreach ($datetime_values as $field => $value) {
1167
-                    $DTM->set($field, $value);
1168
-                }
1169
-                //make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1170
-                $saved_dtts[$DTM->ID()] = $DTM;
1171
-            } else {
1172
-                $DTM = EE_Registry::instance()->load_class(
1173
-                    'Datetime',
1174
-                    array($datetime_values, $evtobj->get_timezone(), $incoming_date_formats),
1175
-                    false,
1176
-                    false
1177
-                );
1178
-                foreach ($datetime_values as $field => $value) {
1179
-                    $DTM->set($field, $value);
1180
-                }
1181
-            }
1182
-            $DTM->save();
1183
-            $DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
1184
-            //load DTT helper
1185
-            //before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1186
-            if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
1187
-                $DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
1188
-                $DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1189
-                $DTT->save();
1190
-            }
1191
-            //now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
1192
-            $saved_dtt = $DTT;
1193
-            $success = ! $success ? $success : $DTT;
1194
-            //if ANY of these updates fail then we want the appropriate global error message.
1195
-            // //todo this is actually sucky we need a better error message but this is what it is for now.
1196
-        }
1197
-        //no dtts get deleted so we don't do any of that logic here.
1198
-        //update tickets next
1199
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
1200
-        foreach ($data['edit_tickets'] as $row => $tkt) {
1201
-            $incoming_date_formats = array('Y-m-d', 'h:i a');
1202
-            $update_prices = false;
1203
-            $ticket_price = isset($data['edit_prices'][$row][1]['PRC_amount'])
1204
-                ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1205
-            // trim inputs to ensure any excess whitespace is removed.
1206
-            $tkt = array_map('trim', $tkt);
1207
-            if (empty($tkt['TKT_start_date'])) {
1208
-                //let's use now in the set timezone.
1209
-                $now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1210
-                $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1211
-            }
1212
-            if (empty($tkt['TKT_end_date'])) {
1213
-                //use the start date of the first datetime
1214
-                $dtt = $evtobj->first_datetime();
1215
-                $tkt['TKT_end_date'] = $dtt->start_date_and_time(
1216
-                    $incoming_date_formats[0],
1217
-                    $incoming_date_formats[1]
1218
-                );
1219
-            }
1220
-            $TKT_values = array(
1221
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
1222
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
1223
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
1224
-                'TKT_description' => ! empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '',
1225
-                'TKT_start_date'  => $tkt['TKT_start_date'],
1226
-                'TKT_end_date'    => $tkt['TKT_end_date'],
1227
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'],
1228
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'],
1229
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
1230
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
1231
-                'TKT_row'         => $row,
1232
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row,
1233
-                'TKT_price'       => $ticket_price,
1234
-            );
1235
-            //if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1236
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
1237
-                $TKT_values['TKT_ID'] = 0;
1238
-                $TKT_values['TKT_is_default'] = 0;
1239
-                $TKT_values['TKT_price'] = $ticket_price;
1240
-                $update_prices = true;
1241
-            }
1242
-            //if we have a TKT_ID then we need to get that existing TKT_obj and update it
1243
-            //we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1244
-            //keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1245
-            if ( ! empty($tkt['TKT_ID'])) {
1246
-                $TKT = EE_Registry::instance()
1247
-                                  ->load_model('Ticket', array($evtobj->get_timezone()))
1248
-                                  ->get_one_by_ID($tkt['TKT_ID']);
1249
-                if ($TKT instanceof EE_Ticket) {
1250
-                    $ticket_sold = $TKT->count_related(
1251
-                        'Registration',
1252
-                        array(
1253
-                            array(
1254
-                                'STS_ID' => array(
1255
-                                    'NOT IN',
1256
-                                    array(EEM_Registration::status_id_incomplete),
1257
-                                ),
1258
-                            ),
1259
-                        )
1260
-                    ) > 0 ? true : false;
1261
-                    //let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1262
-                    $create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price')
1263
-                                      && ! $TKT->get(
1264
-                        'TKT_deleted'
1265
-                    ) ? true : false;
1266
-                    $TKT->set_date_format($incoming_date_formats[0]);
1267
-                    $TKT->set_time_format($incoming_date_formats[1]);
1268
-                    //set new values
1269
-                    foreach ($TKT_values as $field => $value) {
1270
-                        if ($field == 'TKT_qty') {
1271
-                            $TKT->set_qty($value);
1272
-                        } else {
1273
-                            $TKT->set($field, $value);
1274
-                        }
1275
-                    }
1276
-                    //if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1277
-                    if ($create_new_TKT) {
1278
-                        //archive the old ticket first
1279
-                        $TKT->set('TKT_deleted', 1);
1280
-                        $TKT->save();
1281
-                        //make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1282
-                        $saved_tickets[$TKT->ID()] = $TKT;
1283
-                        //create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1284
-                        $TKT = clone $TKT;
1285
-                        $TKT->set('TKT_ID', 0);
1286
-                        $TKT->set('TKT_deleted', 0);
1287
-                        $TKT->set('TKT_price', $ticket_price);
1288
-                        $TKT->set('TKT_sold', 0);
1289
-                        //now we need to make sure that $new prices are created as well and attached to new ticket.
1290
-                        $update_prices = true;
1291
-                    }
1292
-                    //make sure price is set if it hasn't been already
1293
-                    $TKT->set('TKT_price', $ticket_price);
1294
-                }
1295
-            } else {
1296
-                //no TKT_id so a new TKT
1297
-                $TKT_values['TKT_price'] = $ticket_price;
1298
-                $TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), false, false);
1299
-                if ($TKT instanceof EE_Ticket) {
1300
-                    //need to reset values to properly account for the date formats
1301
-                    $TKT->set_date_format($incoming_date_formats[0]);
1302
-                    $TKT->set_time_format($incoming_date_formats[1]);
1303
-                    $TKT->set_timezone($evtobj->get_timezone());
1304
-                    //set new values
1305
-                    foreach ($TKT_values as $field => $value) {
1306
-                        if ($field == 'TKT_qty') {
1307
-                            $TKT->set_qty($value);
1308
-                        } else {
1309
-                            $TKT->set($field, $value);
1310
-                        }
1311
-                    }
1312
-                    $update_prices = true;
1313
-                }
1314
-            }
1315
-            // cap ticket qty by datetime reg limits
1316
-            $TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
1317
-            //update ticket.
1318
-            $TKT->save();
1319
-            //before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1320
-            if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
1321
-                $TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
1322
-                $TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1323
-                $TKT->save();
1324
-            }
1325
-            //initially let's add the ticket to the dtt
1326
-            $saved_dtt->_add_relation_to($TKT, 'Ticket');
1327
-            $saved_tickets[$TKT->ID()] = $TKT;
1328
-            //add prices to ticket
1329
-            $this->_add_prices_to_ticket($data['edit_prices'][$row], $TKT, $update_prices);
1330
-        }
1331
-        //however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1332
-        $old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
1333
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1334
-        foreach ($tickets_removed as $id) {
1335
-            $id = absint($id);
1336
-            //get the ticket for this id
1337
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1338
-            //need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1339
-            $dtts = $tkt_to_remove->get_many_related('Datetime');
1340
-            foreach ($dtts as $dtt) {
1341
-                $tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1342
-            }
1343
-            //need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1344
-            $tkt_to_remove->delete_related_permanently('Price');
1345
-            //finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1346
-            $tkt_to_remove->delete_permanently();
1347
-        }
1348
-        return array($saved_dtt, $saved_tickets);
1349
-    }
1350
-
1351
-
1352
-
1353
-    /**
1354
-     * This attaches a list of given prices to a ticket.
1355
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
1356
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
1357
-     * price info and prices are automatically "archived" via the ticket.
1358
-     *
1359
-     * @access  private
1360
-     * @param array     $prices     Array of prices from the form.
1361
-     * @param EE_Ticket $ticket     EE_Ticket object that prices are being attached to.
1362
-     * @param bool      $new_prices Whether attach existing incoming prices or create new ones.
1363
-     * @return  void
1364
-     */
1365
-    private function _add_prices_to_ticket($prices, EE_Ticket $ticket, $new_prices = false)
1366
-    {
1367
-        foreach ($prices as $row => $prc) {
1368
-            $PRC_values = array(
1369
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
1370
-                'PRT_ID'         => ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null,
1371
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
1372
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
1373
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
1374
-                'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1375
-                'PRC_order'      => $row,
1376
-            );
1377
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
1378
-                $PRC_values['PRC_ID'] = 0;
1379
-                $PRC = EE_Registry::instance()->load_class('Price', array($PRC_values), false, false);
1380
-            } else {
1381
-                $PRC = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
1382
-                //update this price with new values
1383
-                foreach ($PRC_values as $field => $newprc) {
1384
-                    $PRC->set($field, $newprc);
1385
-                }
1386
-                $PRC->save();
1387
-            }
1388
-            $ticket->_add_relation_to($PRC, 'Price');
1389
-        }
1390
-    }
1391
-
1392
-
1393
-
1394
-    /**
1395
-     * Add in our autosave ajax handlers
1396
-     *
1397
-     */
1398
-    protected function _ee_autosave_create_new()
1399
-    {
1400
-    }
1401
-
1402
-
1403
-    /**
1404
-     * More autosave handlers.
1405
-     */
1406
-    protected function _ee_autosave_edit()
1407
-    {
1408
-        return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1409
-    }
1410
-
1411
-
1412
-
1413
-    /**
1414
-     *    _generate_publish_box_extra_content
1415
-     */
1416
-    private function _generate_publish_box_extra_content()
1417
-    {
1418
-        //load formatter helper
1419
-        //args for getting related registrations
1420
-        $approved_query_args = array(
1421
-            array(
1422
-                'REG_deleted' => 0,
1423
-                'STS_ID'      => EEM_Registration::status_id_approved,
1424
-            ),
1425
-        );
1426
-        $not_approved_query_args = array(
1427
-            array(
1428
-                'REG_deleted' => 0,
1429
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1430
-            ),
1431
-        );
1432
-        $pending_payment_query_args = array(
1433
-            array(
1434
-                'REG_deleted' => 0,
1435
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1436
-            ),
1437
-        );
1438
-        // publish box
1439
-        $publish_box_extra_args = array(
1440
-            'view_approved_reg_url'        => add_query_arg(
1441
-                array(
1442
-                    'action'      => 'default',
1443
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1444
-                    '_reg_status' => EEM_Registration::status_id_approved,
1445
-                ),
1446
-                REG_ADMIN_URL
1447
-            ),
1448
-            'view_not_approved_reg_url'    => add_query_arg(
1449
-                array(
1450
-                    'action'      => 'default',
1451
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1452
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1453
-                ),
1454
-                REG_ADMIN_URL
1455
-            ),
1456
-            'view_pending_payment_reg_url' => add_query_arg(
1457
-                array(
1458
-                    'action'      => 'default',
1459
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1460
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1461
-                ),
1462
-                REG_ADMIN_URL
1463
-            ),
1464
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1465
-                'Registration',
1466
-                $approved_query_args
1467
-            ),
1468
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1469
-                'Registration',
1470
-                $not_approved_query_args
1471
-            ),
1472
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1473
-                'Registration',
1474
-                $pending_payment_query_args
1475
-            ),
1476
-            'misc_pub_section_class'       => apply_filters(
1477
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1478
-                'misc-pub-section'
1479
-            ),
1480
-        );
1481
-        ob_start();
1482
-        do_action(
1483
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1484
-            $this->_cpt_model_obj
1485
-        );
1486
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1487
-        // load template
1488
-        EEH_Template::display_template(
1489
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1490
-            $publish_box_extra_args
1491
-        );
1492
-    }
1493
-
1494
-
1495
-
1496
-    /**
1497
-     * @return EE_Event
1498
-     */
1499
-    public function get_event_object()
1500
-    {
1501
-        return $this->_cpt_model_obj;
1502
-    }
1503
-
1504
-
1505
-
1506
-
1507
-    /** METABOXES * */
1508
-    /**
1509
-     * _register_event_editor_meta_boxes
1510
-     * add all metaboxes related to the event_editor
1511
-     *
1512
-     * @return void
1513
-     */
1514
-    protected function _register_event_editor_meta_boxes()
1515
-    {
1516
-        $this->verify_cpt_object();
1517
-        add_meta_box(
1518
-            'espresso_event_editor_tickets',
1519
-            esc_html__('Event Datetime & Ticket', 'event_espresso'),
1520
-            array($this, 'ticket_metabox'),
1521
-            $this->page_slug,
1522
-            'normal',
1523
-            'high'
1524
-        );
1525
-        add_meta_box(
1526
-            'espresso_event_editor_event_options',
1527
-            esc_html__('Event Registration Options', 'event_espresso'),
1528
-            array($this, 'registration_options_meta_box'),
1529
-            $this->page_slug,
1530
-            'side',
1531
-            'default'
1532
-        );
1533
-        // NOTE: if you're looking for other metaboxes in here,
1534
-        // where a metabox has a related management page in the admin
1535
-        // you will find it setup in the related management page's "_Hooks" file.
1536
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1537
-    }
1538
-
1539
-
1540
-    /**
1541
-     * @throws DomainException
1542
-     * @throws EE_Error
1543
-     */
1544
-    public function ticket_metabox()
1545
-    {
1546
-        $existing_datetime_ids = $existing_ticket_ids = array();
1547
-        //defaults for template args
1548
-        $template_args = array(
1549
-            'existing_datetime_ids'    => '',
1550
-            'event_datetime_help_link' => '',
1551
-            'ticket_options_help_link' => '',
1552
-            'time'                     => null,
1553
-            'ticket_rows'              => '',
1554
-            'existing_ticket_ids'      => '',
1555
-            'total_ticket_rows'        => 1,
1556
-            'ticket_js_structure'      => '',
1557
-            'trash_icon'               => 'ee-lock-icon',
1558
-            'disabled'                 => '',
1559
-        );
1560
-        $event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1561
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1562
-        /**
1563
-         * 1. Start with retrieving Datetimes
1564
-         * 2. Fore each datetime get related tickets
1565
-         * 3. For each ticket get related prices
1566
-         */
1567
-        $times = EE_Registry::instance()->load_model('Datetime')->get_all_event_dates($event_id);
1568
-        /** @type EE_Datetime $first_datetime */
1569
-        $first_datetime = reset($times);
1570
-        //do we get related tickets?
1571
-        if ($first_datetime instanceof EE_Datetime
1572
-            && $first_datetime->ID() !== 0
1573
-        ) {
1574
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1575
-            $template_args['time'] = $first_datetime;
1576
-            $related_tickets = $first_datetime->tickets(
1577
-                array(
1578
-                    array('OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0)),
1579
-                    'default_where_conditions' => 'none',
1580
-                )
1581
-            );
1582
-            if ( ! empty($related_tickets)) {
1583
-                $template_args['total_ticket_rows'] = count($related_tickets);
1584
-                $row = 0;
1585
-                foreach ($related_tickets as $ticket) {
1586
-                    $existing_ticket_ids[] = $ticket->get('TKT_ID');
1587
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1588
-                    $row++;
1589
-                }
1590
-            } else {
1591
-                $template_args['total_ticket_rows'] = 1;
1592
-                /** @type EE_Ticket $ticket */
1593
-                $ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1594
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1595
-            }
1596
-        } else {
1597
-            $template_args['time'] = $times[0];
1598
-            /** @type EE_Ticket $ticket */
1599
-            $ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
1600
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket[1]);
1601
-            // NOTE: we're just sending the first default row
1602
-            // (decaf can't manage default tickets so this should be sufficient);
1603
-        }
1604
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1605
-            'event_editor_event_datetimes_help_tab'
1606
-        );
1607
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1608
-        $template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1609
-        $template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1610
-        $template_args['ticket_js_structure'] = $this->_get_ticket_row(
1611
-            EE_Registry::instance()->load_model('Ticket')->create_default_object(),
1612
-            true
1613
-        );
1614
-        $template = apply_filters(
1615
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1616
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1617
-        );
1618
-        EEH_Template::display_template($template, $template_args);
1619
-    }
1620
-
1621
-
1622
-
1623
-    /**
1624
-     * Setup an individual ticket form for the decaf event editor page
1625
-     *
1626
-     * @access private
1627
-     * @param  EE_Ticket $ticket   the ticket object
1628
-     * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1629
-     * @param int        $row
1630
-     * @return string generated html for the ticket row.
1631
-     */
1632
-    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1633
-    {
1634
-        $template_args = array(
1635
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1636
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1637
-                : '',
1638
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1639
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1640
-            'TKT_name'            => $ticket->get('TKT_name'),
1641
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1642
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1643
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1644
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1645
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1646
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1647
-            'trash_icon'          => ($skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')))
1648
-                                     && ( ! empty($ticket) && $ticket->get('TKT_sold') === 0)
1649
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1650
-            'disabled'            => $skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1651
-                : ' disabled=disabled',
1652
-        );
1653
-        $price = $ticket->ID() !== 0
1654
-            ? $ticket->get_first_related('Price', array('default_where_conditions' => 'none'))
1655
-            : EE_Registry::instance()->load_model('Price')->create_default_object();
1656
-        $price_args = array(
1657
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1658
-            'PRC_amount'            => $price->get('PRC_amount'),
1659
-            'PRT_ID'                => $price->get('PRT_ID'),
1660
-            'PRC_ID'                => $price->get('PRC_ID'),
1661
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1662
-        );
1663
-        //make sure we have default start and end dates if skeleton
1664
-        //handle rows that should NOT be empty
1665
-        if (empty($template_args['TKT_start_date'])) {
1666
-            //if empty then the start date will be now.
1667
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1668
-        }
1669
-        if (empty($template_args['TKT_end_date'])) {
1670
-            //get the earliest datetime (if present);
1671
-            $earliest_dtt = $this->_cpt_model_obj->ID() > 0
1672
-                ? $this->_cpt_model_obj->get_first_related(
1673
-                    'Datetime',
1674
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1675
-                )
1676
-                : null;
1677
-            if ( ! empty($earliest_dtt)) {
1678
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1679
-            } else {
1680
-                $template_args['TKT_end_date'] = date(
1681
-                    'Y-m-d h:i a',
1682
-                    mktime(0, 0, 0, date("m"), date("d") + 7, date("Y"))
1683
-                );
1684
-            }
1685
-        }
1686
-        $template_args = array_merge($template_args, $price_args);
1687
-        $template = apply_filters(
1688
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1689
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1690
-            $ticket
1691
-        );
1692
-        return EEH_Template::display_template($template, $template_args, true);
1693
-    }
1694
-
1695
-
1696
-    /**
1697
-     * @throws DomainException
1698
-     */
1699
-    public function registration_options_meta_box()
1700
-    {
1701
-        $yes_no_values = array(
1702
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
1703
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
1704
-        );
1705
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1706
-            array(
1707
-                EEM_Registration::status_id_cancelled,
1708
-                EEM_Registration::status_id_declined,
1709
-                EEM_Registration::status_id_incomplete,
1710
-            ),
1711
-            true
1712
-        );
1713
-        //$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1714
-        $template_args['_event'] = $this->_cpt_model_obj;
1715
-        $template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
1716
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
1717
-        $template_args['default_registration_status'] = EEH_Form_Fields::select_input(
1718
-            'default_reg_status',
1719
-            $default_reg_status_values,
1720
-            $this->_cpt_model_obj->default_registration_status()
1721
-        );
1722
-        $template_args['display_description'] = EEH_Form_Fields::select_input(
1723
-            'display_desc',
1724
-            $yes_no_values,
1725
-            $this->_cpt_model_obj->display_description()
1726
-        );
1727
-        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1728
-            'display_ticket_selector',
1729
-            $yes_no_values,
1730
-            $this->_cpt_model_obj->display_ticket_selector(),
1731
-            '',
1732
-            '',
1733
-            false
1734
-        );
1735
-        $template_args['additional_registration_options'] = apply_filters(
1736
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1737
-            '',
1738
-            $template_args,
1739
-            $yes_no_values,
1740
-            $default_reg_status_values
1741
-        );
1742
-        EEH_Template::display_template(
1743
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1744
-            $template_args
1745
-        );
1746
-    }
1747
-
1748
-
1749
-
1750
-    /**
1751
-     * _get_events()
1752
-     * This method simply returns all the events (for the given _view and paging)
1753
-     *
1754
-     * @access public
1755
-     * @param int  $per_page     count of items per page (20 default);
1756
-     * @param int  $current_page what is the current page being viewed.
1757
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1758
-     *                           If FALSE then we return an array of event objects
1759
-     *                           that match the given _view and paging parameters.
1760
-     * @return array an array of event objects.
1761
-     */
1762
-    public function get_events($per_page = 10, $current_page = 1, $count = false)
1763
-    {
1764
-        $EEME = $this->_event_model();
1765
-        $offset = ($current_page - 1) * $per_page;
1766
-        $limit = $count ? null : $offset . ',' . $per_page;
1767
-        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1768
-        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1769
-        if (isset($this->_req_data['month_range'])) {
1770
-            $pieces = explode(' ', $this->_req_data['month_range'], 3);
1771
-            //simulate the FIRST day of the month, that fixes issues for months like February
1772
-            //where PHP doesn't know what to assume for date.
1773
-            //@see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1774
-            $month_r = ! empty($pieces[0]) ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1775
-            $year_r = ! empty($pieces[1]) ? $pieces[1] : '';
1776
-        }
1777
-        $where = array();
1778
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1779
-        //determine what post_status our condition will have for the query.
1780
-        switch ($status) {
1781
-            case 'month' :
1782
-            case 'today' :
1783
-            case null :
1784
-            case 'all' :
1785
-                break;
1786
-            case 'draft' :
1787
-                $where['status'] = array('IN', array('draft', 'auto-draft'));
1788
-                break;
1789
-            default :
1790
-                $where['status'] = $status;
1791
-        }
1792
-        //categories?
1793
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1794
-            ? $this->_req_data['EVT_CAT'] : null;
1795
-        if ( ! empty ($category)) {
1796
-            $where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1797
-            $where['Term_Taxonomy.term_id'] = $category;
1798
-        }
1799
-        //date where conditions
1800
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1801
-        if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1802
-            $DateTime = new DateTime(
1803
-                $year_r . '-' . $month_r . '-01 00:00:00',
1804
-                new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1805
-            );
1806
-            $start = $DateTime->format(implode(' ', $start_formats));
1807
-            $end = $DateTime->setDate($year_r, $month_r, $DateTime
1808
-                ->format('t'))->setTime(23, 59, 59)
1809
-                            ->format(implode(' ', $start_formats));
1810
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1811
-        } else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1812
-            $DateTime = new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1813
-            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1814
-            $end = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1815
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1816
-        } else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'month') {
1817
-            $now = date('Y-m-01');
1818
-            $DateTime = new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1819
-            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1820
-            $end = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1821
-                            ->setTime(23, 59, 59)
1822
-                            ->format(implode(' ', $start_formats));
1823
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1824
-        }
1825
-        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1826
-            $where['EVT_wp_user'] = get_current_user_id();
1827
-        } else {
1828
-            if ( ! isset($where['status'])) {
1829
-                if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1830
-                    $where['OR'] = array(
1831
-                        'status*restrict_private' => array('!=', 'private'),
1832
-                        'AND'                     => array(
1833
-                            'status*inclusive' => array('=', 'private'),
1834
-                            'EVT_wp_user'      => get_current_user_id(),
1835
-                        ),
1836
-                    );
1837
-                }
1838
-            }
1839
-        }
1840
-        if (isset($this->_req_data['EVT_wp_user'])) {
1841
-            if ($this->_req_data['EVT_wp_user'] != get_current_user_id()
1842
-                && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1843
-            ) {
1844
-                $where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1845
-            }
1846
-        }
1847
-        //search query handling
1848
-        if (isset($this->_req_data['s'])) {
1849
-            $search_string = '%' . $this->_req_data['s'] . '%';
1850
-            $where['OR'] = array(
1851
-                'EVT_name'       => array('LIKE', $search_string),
1852
-                'EVT_desc'       => array('LIKE', $search_string),
1853
-                'EVT_short_desc' => array('LIKE', $search_string),
1854
-            );
1855
-        }
1856
-        $where = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data);
1857
-        $query_params = apply_filters(
1858
-            'FHEE__Events_Admin_Page__get_events__query_params',
1859
-            array(
1860
-                $where,
1861
-                'limit'    => $limit,
1862
-                'order_by' => $orderby,
1863
-                'order'    => $order,
1864
-                'group_by' => 'EVT_ID',
1865
-            ),
1866
-            $this->_req_data
1867
-        );
1868
-        //let's first check if we have special requests coming in.
1869
-        if (isset($this->_req_data['active_status'])) {
1870
-            switch ($this->_req_data['active_status']) {
1871
-                case 'upcoming' :
1872
-                    return $EEME->get_upcoming_events($query_params, $count);
1873
-                    break;
1874
-                case 'expired' :
1875
-                    return $EEME->get_expired_events($query_params, $count);
1876
-                    break;
1877
-                case 'active' :
1878
-                    return $EEME->get_active_events($query_params, $count);
1879
-                    break;
1880
-                case 'inactive' :
1881
-                    return $EEME->get_inactive_events($query_params, $count);
1882
-                    break;
1883
-            }
1884
-        }
1885
-        $events = $count ? $EEME->count(array($where), 'EVT_ID', true) : $EEME->get_all($query_params);
1886
-        return $events;
1887
-    }
1888
-
1889
-
1890
-
1891
-    /**
1892
-     * handling for WordPress CPT actions (trash, restore, delete)
1893
-     *
1894
-     * @param string $post_id
1895
-     */
1896
-    public function trash_cpt_item($post_id)
1897
-    {
1898
-        $this->_req_data['EVT_ID'] = $post_id;
1899
-        $this->_trash_or_restore_event('trash', false);
1900
-    }
1901
-
1902
-
1903
-
1904
-    /**
1905
-     * @param string $post_id
1906
-     */
1907
-    public function restore_cpt_item($post_id)
1908
-    {
1909
-        $this->_req_data['EVT_ID'] = $post_id;
1910
-        $this->_trash_or_restore_event('draft', false);
1911
-    }
1912
-
1913
-
1914
-
1915
-    /**
1916
-     * @param string $post_id
1917
-     */
1918
-    public function delete_cpt_item($post_id)
1919
-    {
1920
-        $this->_req_data['EVT_ID'] = $post_id;
1921
-        $this->_delete_event(false);
1922
-    }
1923
-
1924
-
1925
-
1926
-    /**
1927
-     * _trash_or_restore_event
1928
-     *
1929
-     * @access protected
1930
-     * @param  string $event_status
1931
-     * @param bool    $redirect_after
1932
-     */
1933
-    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
1934
-    {
1935
-        //determine the event id and set to array.
1936
-        $EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : false;
1937
-        // loop thru events
1938
-        if ($EVT_ID) {
1939
-            // clean status
1940
-            $event_status = sanitize_key($event_status);
1941
-            // grab status
1942
-            if ( ! empty($event_status)) {
1943
-                $success = $this->_change_event_status($EVT_ID, $event_status);
1944
-            } else {
1945
-                $success = false;
1946
-                $msg = esc_html__(
1947
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1948
-                    'event_espresso'
1949
-                );
1950
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1951
-            }
1952
-        } else {
1953
-            $success = false;
1954
-            $msg = esc_html__(
1955
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
1956
-                'event_espresso'
1957
-            );
1958
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1959
-        }
1960
-        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1961
-        if ($redirect_after) {
1962
-            $this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
1963
-        }
1964
-    }
1965
-
1966
-
1967
-
1968
-    /**
1969
-     * _trash_or_restore_events
1970
-     *
1971
-     * @access protected
1972
-     * @param  string $event_status
1973
-     * @return void
1974
-     */
1975
-    protected function _trash_or_restore_events($event_status = 'trash')
1976
-    {
1977
-        // clean status
1978
-        $event_status = sanitize_key($event_status);
1979
-        // grab status
1980
-        if ( ! empty($event_status)) {
1981
-            $success = true;
1982
-            //determine the event id and set to array.
1983
-            $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array)$this->_req_data['EVT_IDs'] : array();
1984
-            // loop thru events
1985
-            foreach ($EVT_IDs as $EVT_ID) {
1986
-                if ($EVT_ID = absint($EVT_ID)) {
1987
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
1988
-                    $success = $results !== false ? $success : false;
1989
-                } else {
1990
-                    $msg = sprintf(
1991
-                        esc_html__(
1992
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
1993
-                            'event_espresso'
1994
-                        ),
1995
-                        $EVT_ID
1996
-                    );
1997
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1998
-                    $success = false;
1999
-                }
2000
-            }
2001
-        } else {
2002
-            $success = false;
2003
-            $msg = esc_html__(
2004
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2005
-                'event_espresso'
2006
-            );
2007
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2008
-        }
2009
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2010
-        $success = $success ? 2 : false;
2011
-        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
2012
-        $this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
2013
-    }
2014
-
2015
-
2016
-
2017
-    /**
2018
-     * _trash_or_restore_events
2019
-     *
2020
-     * @access  private
2021
-     * @param  int    $EVT_ID
2022
-     * @param  string $event_status
2023
-     * @return bool
2024
-     */
2025
-    private function _change_event_status($EVT_ID = 0, $event_status = '')
2026
-    {
2027
-        // grab event id
2028
-        if ( ! $EVT_ID) {
2029
-            $msg = esc_html__(
2030
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2031
-                'event_espresso'
2032
-            );
2033
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2034
-            return false;
2035
-        }
2036
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2037
-        // clean status
2038
-        $event_status = sanitize_key($event_status);
2039
-        // grab status
2040
-        if (empty($event_status)) {
2041
-            $msg = esc_html__(
2042
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2043
-                'event_espresso'
2044
-            );
2045
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2046
-            return false;
2047
-        }
2048
-        // was event trashed or restored ?
2049
-        switch ($event_status) {
2050
-            case 'draft' :
2051
-                $action = 'restored from the trash';
2052
-                $hook = 'AHEE_event_restored_from_trash';
2053
-                break;
2054
-            case 'trash' :
2055
-                $action = 'moved to the trash';
2056
-                $hook = 'AHEE_event_moved_to_trash';
2057
-                break;
2058
-            default :
2059
-                $action = 'updated';
2060
-                $hook = false;
2061
-        }
2062
-        //use class to change status
2063
-        $this->_cpt_model_obj->set_status($event_status);
2064
-        $success = $this->_cpt_model_obj->save();
2065
-        if ($success === false) {
2066
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2067
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2068
-            return false;
2069
-        }
2070
-        if ($hook) {
2071
-            do_action($hook);
2072
-        }
2073
-        return true;
2074
-    }
2075
-
2076
-
2077
-
2078
-    /**
2079
-     * _delete_event
2080
-     *
2081
-     * @access protected
2082
-     * @param bool $redirect_after
2083
-     */
2084
-    protected function _delete_event($redirect_after = true)
2085
-    {
2086
-        //determine the event id and set to array.
2087
-        $EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : null;
2088
-        $EVT_ID = isset($this->_req_data['post']) ? absint($this->_req_data['post']) : $EVT_ID;
2089
-        // loop thru events
2090
-        if ($EVT_ID) {
2091
-            $success = $this->_permanently_delete_event($EVT_ID);
2092
-            // get list of events with no prices
2093
-            $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2094
-            // remove this event from the list of events with no prices
2095
-            if (isset($espresso_no_ticket_prices[$EVT_ID])) {
2096
-                unset($espresso_no_ticket_prices[$EVT_ID]);
2097
-            }
2098
-            update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2099
-        } else {
2100
-            $success = false;
2101
-            $msg = esc_html__(
2102
-                'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2103
-                'event_espresso'
2104
-            );
2105
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2106
-        }
2107
-        if ($redirect_after) {
2108
-            $this->_redirect_after_action(
2109
-                $success,
2110
-                'Event',
2111
-                'deleted',
2112
-                array('action' => 'default', 'status' => 'trash')
2113
-            );
2114
-        }
2115
-    }
2116
-
2117
-
2118
-
2119
-    /**
2120
-     * _delete_events
2121
-     *
2122
-     * @access protected
2123
-     * @return void
2124
-     */
2125
-    protected function _delete_events()
2126
-    {
2127
-        $success = true;
2128
-        // get list of events with no prices
2129
-        $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2130
-        //determine the event id and set to array.
2131
-        $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array)$this->_req_data['EVT_IDs'] : array();
2132
-        // loop thru events
2133
-        foreach ($EVT_IDs as $EVT_ID) {
2134
-            $EVT_ID = absint($EVT_ID);
2135
-            if ($EVT_ID) {
2136
-                $results = $this->_permanently_delete_event($EVT_ID);
2137
-                $success = $results !== false ? $success : false;
2138
-                // remove this event from the list of events with no prices
2139
-                unset($espresso_no_ticket_prices[$EVT_ID]);
2140
-            } else {
2141
-                $success = false;
2142
-                $msg = esc_html__(
2143
-                    'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2144
-                    'event_espresso'
2145
-                );
2146
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2147
-            }
2148
-        }
2149
-        update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2150
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2151
-        $success = $success ? 2 : false;
2152
-        $this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
2153
-    }
2154
-
2155
-
2156
-
2157
-    /**
2158
-     * _permanently_delete_event
2159
-     *
2160
-     * @access  private
2161
-     * @param  int $EVT_ID
2162
-     * @return bool
2163
-     */
2164
-    private function _permanently_delete_event($EVT_ID = 0)
2165
-    {
2166
-        // grab event id
2167
-        if ( ! $EVT_ID) {
2168
-            $msg = esc_html__(
2169
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2170
-                'event_espresso'
2171
-            );
2172
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2173
-            return false;
2174
-        }
2175
-        if (
2176
-            ! $this->_cpt_model_obj instanceof EE_Event
2177
-            || $this->_cpt_model_obj->ID() !== $EVT_ID
2178
-        ) {
2179
-            $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2180
-        }
2181
-        if ( ! $this->_cpt_model_obj instanceof EE_Event) {
2182
-            return false;
2183
-        }
2184
-        //need to delete related tickets and prices first.
2185
-        $datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
2186
-        foreach ($datetimes as $datetime) {
2187
-            $this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
2188
-            $tickets = $datetime->get_many_related('Ticket');
2189
-            foreach ($tickets as $ticket) {
2190
-                $ticket->_remove_relation_to($datetime, 'Datetime');
2191
-                $ticket->delete_related_permanently('Price');
2192
-                $ticket->delete_permanently();
2193
-            }
2194
-            $datetime->delete();
2195
-        }
2196
-        //what about related venues or terms?
2197
-        $venues = $this->_cpt_model_obj->get_many_related('Venue');
2198
-        foreach ($venues as $venue) {
2199
-            $this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
2200
-        }
2201
-        //any attached question groups?
2202
-        $question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2203
-        if ( ! empty($question_groups)) {
2204
-            foreach ($question_groups as $question_group) {
2205
-                $this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2206
-            }
2207
-        }
2208
-        //Message Template Groups
2209
-        $this->_cpt_model_obj->_remove_relations('Message_Template_Group');
2210
-        /** @type EE_Term_Taxonomy[] $term_taxonomies */
2211
-        $term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
2212
-        foreach ($term_taxonomies as $term_taxonomy) {
2213
-            $this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
2214
-        }
2215
-        $success = $this->_cpt_model_obj->delete_permanently();
2216
-        // did it all go as planned ?
2217
-        if ($success) {
2218
-            $msg = sprintf(esc_html__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2219
-            EE_Error::add_success($msg);
2220
-        } else {
2221
-            $msg = sprintf(
2222
-                esc_html__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'),
2223
-                $EVT_ID
2224
-            );
2225
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
-            return false;
2227
-        }
2228
-        do_action('AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID);
2229
-        return true;
2230
-    }
2231
-
2232
-
2233
-
2234
-    /**
2235
-     * get total number of events
2236
-     *
2237
-     * @access public
2238
-     * @return int
2239
-     */
2240
-    public function total_events()
2241
-    {
2242
-        $count = EEM_Event::instance()->count(array('caps' => 'read_admin'), 'EVT_ID', true);
2243
-        return $count;
2244
-    }
2245
-
2246
-
2247
-
2248
-    /**
2249
-     * get total number of draft events
2250
-     *
2251
-     * @access public
2252
-     * @return int
2253
-     */
2254
-    public function total_events_draft()
2255
-    {
2256
-        $where = array(
2257
-            'status' => array('IN', array('draft', 'auto-draft')),
2258
-        );
2259
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2260
-        return $count;
2261
-    }
2262
-
2263
-
2264
-
2265
-    /**
2266
-     * get total number of trashed events
2267
-     *
2268
-     * @access public
2269
-     * @return int
2270
-     */
2271
-    public function total_trashed_events()
2272
-    {
2273
-        $where = array(
2274
-            'status' => 'trash',
2275
-        );
2276
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2277
-        return $count;
2278
-    }
2279
-
2280
-
2281
-    /**
2282
-     *    _default_event_settings
2283
-     *    This generates the Default Settings Tab
2284
-     *
2285
-     * @return void
2286
-     * @throws EE_Error
2287
-     */
2288
-    protected function _default_event_settings()
2289
-    {
2290
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2291
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
2292
-        $this->_template_args['admin_page_content'] = $this->_default_event_settings_form()->get_html();
2293
-        $this->display_admin_page_with_sidebar();
2294
-    }
2295
-
2296
-
2297
-    /**
2298
-     * Return the form for event settings.
2299
-     * @return EE_Form_Section_Proper
2300
-     */
2301
-    protected function _default_event_settings_form()
2302
-    {
2303
-        $registration_config = EE_Registry::instance()->CFG->registration;
2304
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2305
-        //exclude
2306
-            array(
2307
-                EEM_Registration::status_id_cancelled,
2308
-                EEM_Registration::status_id_declined,
2309
-                EEM_Registration::status_id_incomplete,
2310
-                EEM_Registration::status_id_wait_list,
2311
-            ),
2312
-            true
2313
-        );
2314
-        return new EE_Form_Section_Proper(
2315
-            array(
2316
-                'name' => 'update_default_event_settings',
2317
-                'html_id' => 'update_default_event_settings',
2318
-                'html_class' => 'form-table',
2319
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2320
-                'subsections' => apply_filters(
2321
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2322
-                    array(
2323
-                        'default_reg_status' => new EE_Select_Input(
2324
-                            $registration_stati_for_selection,
2325
-                            array(
2326
-                                'default' => isset($registration_config->default_STS_ID)
2327
-                                             && array_key_exists(
2328
-                                                $registration_config->default_STS_ID,
2329
-                                                $registration_stati_for_selection
2330
-                                             )
2331
-                                            ? sanitize_text_field($registration_config->default_STS_ID)
2332
-                                            : EEM_Registration::status_id_pending_payment,
2333
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2334
-                                                    . EEH_Template::get_help_tab_link(
2335
-                                                        'default_settings_status_help_tab'
2336
-                                                    ),
2337
-                                'html_help_text' => esc_html__(
2338
-                                    'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2339
-                                    'event_espresso'
2340
-                                )
2341
-                            )
2342
-                        ),
2343
-                        'default_max_tickets' => new EE_Integer_Input(
2344
-                            array(
2345
-                                'default' => isset($registration_config->default_maximum_number_of_tickets)
2346
-                                    ? $registration_config->default_maximum_number_of_tickets
2347
-                                    : EEM_Event::get_default_additional_limit(),
2348
-                                'html_label_text' => esc_html__(
2349
-                                    'Default Maximum Tickets Allowed Per Order:',
2350
-                                    'event_espresso'
2351
-                                ) . EEH_Template::get_help_tab_link(
2352
-                                    'default_maximum_tickets_help_tab"'
2353
-                                    ),
2354
-                                'html_help_text' => esc_html__(
2355
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2356
-                                    'event_espresso'
2357
-                                )
2358
-                            )
2359
-                        )
2360
-                    )
2361
-                )
2362
-            )
2363
-        );
2364
-    }
2365
-
2366
-
2367
-    /**
2368
-     * _update_default_event_settings
2369
-     *
2370
-     * @access protected
2371
-     * @return void
2372
-     * @throws EE_Error
2373
-     */
2374
-    protected function _update_default_event_settings()
2375
-    {
2376
-        $registration_config = EE_Registry::instance()->CFG->registration;
2377
-        $form = $this->_default_event_settings_form();
2378
-        if ($form->was_submitted()) {
2379
-            $form->receive_form_submission();
2380
-            if ($form->is_valid()) {
2381
-                $valid_data = $form->valid_data();
2382
-                if (isset($valid_data['default_reg_status'])) {
2383
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2384
-                }
2385
-                if (isset($valid_data['default_max_tickets'])) {
2386
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2387
-                }
2388
-                //update because data was valid!
2389
-                EE_Registry::instance()->CFG->update_espresso_config();
2390
-                EE_Error::overwrite_success();
2391
-                EE_Error::add_success(
2392
-                    __('Default Event Settings were updated', 'event_espresso')
2393
-                );
2394
-            }
2395
-        }
2396
-        $this->_redirect_after_action(0, '', '', array('action' => 'default_event_settings'), true);
2397
-    }
2398
-
2399
-
2400
-
2401
-    /*************        Templates        *************/
2402
-    protected function _template_settings()
2403
-    {
2404
-        $this->_admin_page_title = esc_html__('Template Settings (Preview)', 'event_espresso');
2405
-        $this->_template_args['preview_img'] = '<img src="'
2406
-                                               . EVENTS_ASSETS_URL
2407
-                                               . DS
2408
-                                               . 'images'
2409
-                                               . DS
2410
-                                               . 'caffeinated_template_features.jpg" alt="'
2411
-                                               . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2412
-                                               . '" />';
2413
-        $this->_template_args['preview_text'] = '<strong>' . esc_html__(
2414
-                'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2415
-                'event_espresso'
2416
-            ) . '</strong>';
2417
-        $this->display_admin_caf_preview_page('template_settings_tab');
2418
-    }
2419
-
2420
-
2421
-    /** Event Category Stuff **/
2422
-    /**
2423
-     * set the _category property with the category object for the loaded page.
2424
-     *
2425
-     * @access private
2426
-     * @return void
2427
-     */
2428
-    private function _set_category_object()
2429
-    {
2430
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2431
-            return;
2432
-        } //already have the category object so get out.
2433
-        //set default category object
2434
-        $this->_set_empty_category_object();
2435
-        //only set if we've got an id
2436
-        if ( ! isset($this->_req_data['EVT_CAT_ID'])) {
2437
-            return;
2438
-        }
2439
-        $category_id = absint($this->_req_data['EVT_CAT_ID']);
2440
-        $term = get_term($category_id, 'espresso_event_categories');
2441
-        if ( ! empty($term)) {
2442
-            $this->_category->category_name = $term->name;
2443
-            $this->_category->category_identifier = $term->slug;
2444
-            $this->_category->category_desc = $term->description;
2445
-            $this->_category->id = $term->term_id;
2446
-            $this->_category->parent = $term->parent;
2447
-        }
2448
-    }
2449
-
2450
-
2451
-    /**
2452
-     * Clears out category properties.
2453
-     */
2454
-    private function _set_empty_category_object()
2455
-    {
2456
-        $this->_category = new stdClass();
2457
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2458
-        $this->_category->id = $this->_category->parent = 0;
2459
-    }
2460
-
2461
-
2462
-    /**
2463
-     * @throws EE_Error
2464
-     */
2465
-    protected function _category_list_table()
2466
-    {
2467
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2468
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2469
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2470
-                'add_category',
2471
-                'add_category',
2472
-                array(),
2473
-                'add-new-h2'
2474
-            );
2475
-        $this->display_admin_list_table_page_with_sidebar();
2476
-    }
2477
-
2478
-
2479
-
2480
-    /**
2481
-     * Output category details view.
2482
-     */
2483
-    protected function _category_details($view)
2484
-    {
2485
-        //load formatter helper
2486
-        //load field generator helper
2487
-        $route = $view == 'edit' ? 'update_category' : 'insert_category';
2488
-        $this->_set_add_edit_form_tags($route);
2489
-        $this->_set_category_object();
2490
-        $id = ! empty($this->_category->id) ? $this->_category->id : '';
2491
-        $delete_action = 'delete_category';
2492
-        //custom redirect
2493
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2494
-            array('action' => 'category_list'),
2495
-            $this->_admin_base_url
2496
-        );
2497
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2498
-        //take care of contents
2499
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2500
-        $this->display_admin_page_with_sidebar();
2501
-    }
2502
-
2503
-
2504
-
2505
-    /**
2506
-     * Output category details content.
2507
-     */
2508
-    protected function _category_details_content()
2509
-    {
2510
-        $editor_args['category_desc'] = array(
2511
-            'type'          => 'wp_editor',
2512
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2513
-            'class'         => 'my_editor_custom',
2514
-            'wpeditor_args' => array('media_buttons' => false),
2515
-        );
2516
-        $_wp_editor = $this->_generate_admin_form_fields($editor_args, 'array');
2517
-        $all_terms = get_terms(
2518
-            array('espresso_event_categories'),
2519
-            array('hide_empty' => 0, 'exclude' => array($this->_category->id))
2520
-        );
2521
-        //setup category select for term parents.
2522
-        $category_select_values[] = array(
2523
-            'text' => esc_html__('No Parent', 'event_espresso'),
2524
-            'id'   => 0,
2525
-        );
2526
-        foreach ($all_terms as $term) {
2527
-            $category_select_values[] = array(
2528
-                'text' => $term->name,
2529
-                'id'   => $term->term_id,
2530
-            );
2531
-        }
2532
-        $category_select = EEH_Form_Fields::select_input(
2533
-            'category_parent',
2534
-            $category_select_values,
2535
-            $this->_category->parent
2536
-        );
2537
-        $template_args = array(
2538
-            'category'                 => $this->_category,
2539
-            'category_select'          => $category_select,
2540
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2541
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2542
-            'disable'                  => '',
2543
-            'disabled_message'         => false,
2544
-        );
2545
-        $template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2546
-        return EEH_Template::display_template($template, $template_args, true);
2547
-    }
2548
-
2549
-
2550
-    /**
2551
-     * Handles deleting categories.
2552
-     */
2553
-    protected function _delete_categories()
2554
-    {
2555
-        $cat_ids = isset($this->_req_data['EVT_CAT_ID']) ? (array)$this->_req_data['EVT_CAT_ID']
2556
-            : (array)$this->_req_data['category_id'];
2557
-        foreach ($cat_ids as $cat_id) {
2558
-            $this->_delete_category($cat_id);
2559
-        }
2560
-        //doesn't matter what page we're coming from... we're going to the same place after delete.
2561
-        $query_args = array(
2562
-            'action' => 'category_list',
2563
-        );
2564
-        $this->_redirect_after_action(0, '', '', $query_args);
2565
-    }
2566
-
2567
-
2568
-
2569
-    /**
2570
-     * Handles deleting specific category.
2571
-     * @param int $cat_id
2572
-     */
2573
-    protected function _delete_category($cat_id)
2574
-    {
2575
-        $cat_id = absint($cat_id);
2576
-        wp_delete_term($cat_id, 'espresso_event_categories');
2577
-    }
2578
-
2579
-
2580
-
2581
-    /**
2582
-     * Handles triggering the update or insertion of a new category.
2583
-     * @param bool $new_category  true means we're triggering the insert of a new category.
2584
-     */
2585
-    protected function _insert_or_update_category($new_category)
2586
-    {
2587
-        $cat_id = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2588
-        $success = 0; //we already have a success message so lets not send another.
2589
-        if ($cat_id) {
2590
-            $query_args = array(
2591
-                'action'     => 'edit_category',
2592
-                'EVT_CAT_ID' => $cat_id,
2593
-            );
2594
-        } else {
2595
-            $query_args = array('action' => 'add_category');
2596
-        }
2597
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2598
-    }
2599
-
2600
-
2601
-
2602
-    /**
2603
-     * Inserts or updates category
2604
-     * @param bool $update (true indicates we're updating a category).
2605
-     * @return bool|mixed|string
2606
-     */
2607
-    private function _insert_category($update = false)
2608
-    {
2609
-        $cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2610
-        $category_name = isset($this->_req_data['category_name']) ? $this->_req_data['category_name'] : '';
2611
-        $category_desc = isset($this->_req_data['category_desc']) ? $this->_req_data['category_desc'] : '';
2612
-        $category_parent = isset($this->_req_data['category_parent']) ? $this->_req_data['category_parent'] : 0;
2613
-        if (empty($category_name)) {
2614
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2615
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2616
-            return false;
2617
-        }
2618
-        $term_args = array(
2619
-            'name'        => $category_name,
2620
-            'description' => $category_desc,
2621
-            'parent'      => $category_parent,
2622
-        );
2623
-        //was the category_identifier input disabled?
2624
-        if (isset($this->_req_data['category_identifier'])) {
2625
-            $term_args['slug'] = $this->_req_data['category_identifier'];
2626
-        }
2627
-        $insert_ids = $update
2628
-            ? wp_update_term($cat_id, 'espresso_event_categories', $term_args)
2629
-            : wp_insert_term($category_name, 'espresso_event_categories', $term_args);
2630
-        if ( ! is_array($insert_ids)) {
2631
-            $msg = esc_html__(
2632
-                'An error occurred and the category has not been saved to the database.',
2633
-                'event_espresso'
2634
-            );
2635
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2636
-        } else {
2637
-            $cat_id = $insert_ids['term_id'];
2638
-            $msg = sprintf(esc_html__('The category %s was successfully saved', 'event_espresso'), $category_name);
2639
-            EE_Error::add_success($msg);
2640
-        }
2641
-        return $cat_id;
2642
-    }
2643
-
2644
-
2645
-
2646
-    /**
2647
-     * Gets categories or count of categories matching the arguments in the request.
2648
-     * @param int  $per_page
2649
-     * @param int  $current_page
2650
-     * @param bool $count
2651
-     * @return EE_Base_Class[]|EE_Term_Taxonomy[]|int
2652
-     */
2653
-    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2654
-    {
2655
-        //testing term stuff
2656
-        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'Term.term_id';
2657
-        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2658
-        $limit = ($current_page - 1) * $per_page;
2659
-        $where = array('taxonomy' => 'espresso_event_categories');
2660
-        if (isset($this->_req_data['s'])) {
2661
-            $sstr = '%' . $this->_req_data['s'] . '%';
2662
-            $where['OR'] = array(
2663
-                'Term.name'   => array('LIKE', $sstr),
2664
-                'description' => array('LIKE', $sstr),
2665
-            );
2666
-        }
2667
-        $query_params = array(
2668
-            $where,
2669
-            'order_by'   => array($orderby => $order),
2670
-            'limit'      => $limit . ',' . $per_page,
2671
-            'force_join' => array('Term'),
2672
-        );
2673
-        $categories = $count
2674
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2675
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2676
-        return $categories;
2677
-    }
2678
-
2679
-    /* end category stuff */
2680
-    /**************/
2681
-
2682
-
2683
-    /**
2684
-     * Callback for the `ee_save_timezone_setting` ajax action.
2685
-     * @throws EE_Error
2686
-     */
2687
-    public function save_timezonestring_setting()
2688
-    {
2689
-        $timezone_string = isset($this->_req_data['timezone_selected'])
2690
-            ? $this->_req_data['timezone_selected']
2691
-            : '';
2692
-        if  (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false))
2693
-        {
2694
-            EE_Error::add_error(
2695
-                esc_html('An invalid timezone string submitted.', 'event_espresso'),
2696
-                __FILE__, __FUNCTION__, __LINE__
2697
-            );
2698
-            $this->_template_args['error'] = true;
2699
-            $this->_return_json();
2700
-        }
2701
-
2702
-        update_option('timezone_string', $timezone_string);
2703
-        EE_Error::add_success(
2704
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2705
-        );
2706
-        $this->_template_args['success'] = true;
2707
-        $this->_return_json(true, array('action' => 'create_new'));
2708
-    }
394
+				'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
395
+				'require_nonce' => false,
396
+			),
397
+			'default_event_settings' => array(
398
+				'nav'           => array(
399
+					'label' => esc_html__('Default Settings', 'event_espresso'),
400
+					'order' => 40,
401
+				),
402
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
403
+				'labels'        => array(
404
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
405
+				),
406
+				'help_tabs'     => array(
407
+					'default_settings_help_tab'        => array(
408
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
409
+						'filename' => 'events_default_settings',
410
+					),
411
+					'default_settings_status_help_tab' => array(
412
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
413
+						'filename' => 'events_default_settings_status',
414
+					),
415
+					'default_maximum_tickets_help_tab' => array(
416
+						'title' => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
417
+						'filename' => 'events_default_settings_max_tickets',
418
+					)
419
+				),
420
+				'help_tour'     => array('Event_Default_Settings_Help_Tour'),
421
+				'require_nonce' => false,
422
+			),
423
+			//template settings
424
+			'template_settings'      => array(
425
+				'nav'           => array(
426
+					'label' => esc_html__('Templates', 'event_espresso'),
427
+					'order' => 30,
428
+				),
429
+				'metaboxes'     => $this->_default_espresso_metaboxes,
430
+				'help_tabs'     => array(
431
+					'general_settings_templates_help_tab' => array(
432
+						'title'    => esc_html__('Templates', 'event_espresso'),
433
+						'filename' => 'general_settings_templates',
434
+					),
435
+				),
436
+				'help_tour'     => array('Templates_Help_Tour'),
437
+				'require_nonce' => false,
438
+			),
439
+			//event category stuff
440
+			'add_category'           => array(
441
+				'nav'           => array(
442
+					'label'      => esc_html__('Add Category', 'event_espresso'),
443
+					'order'      => 15,
444
+					'persistent' => false,
445
+				),
446
+				'help_tabs'     => array(
447
+					'add_category_help_tab' => array(
448
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
449
+						'filename' => 'events_add_category',
450
+					),
451
+				),
452
+				'help_tour'     => array('Event_Add_Category_Help_Tour'),
453
+				'metaboxes'     => array('_publish_post_box'),
454
+				'require_nonce' => false,
455
+			),
456
+			'edit_category'          => array(
457
+				'nav'           => array(
458
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
459
+					'order'      => 15,
460
+					'persistent' => false,
461
+					'url'        => isset($this->_req_data['EVT_CAT_ID'])
462
+						? add_query_arg(
463
+							array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID']),
464
+							$this->_current_page_view_url
465
+						)
466
+						: $this->_admin_base_url,
467
+				),
468
+				'help_tabs'     => array(
469
+					'edit_category_help_tab' => array(
470
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
471
+						'filename' => 'events_edit_category',
472
+					),
473
+				),
474
+				/*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
475
+				'metaboxes'     => array('_publish_post_box'),
476
+				'require_nonce' => false,
477
+			),
478
+			'category_list'          => array(
479
+				'nav'           => array(
480
+					'label' => esc_html__('Categories', 'event_espresso'),
481
+					'order' => 20,
482
+				),
483
+				'list_table'    => 'Event_Categories_Admin_List_Table',
484
+				'help_tabs'     => array(
485
+					'events_categories_help_tab'                       => array(
486
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
487
+						'filename' => 'events_categories',
488
+					),
489
+					'events_categories_table_column_headings_help_tab' => array(
490
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
491
+						'filename' => 'events_categories_table_column_headings',
492
+					),
493
+					'events_categories_view_help_tab'                  => array(
494
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
495
+						'filename' => 'events_categories_views',
496
+					),
497
+					'events_categories_other_help_tab'                 => array(
498
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
499
+						'filename' => 'events_categories_other',
500
+					),
501
+				),
502
+				'help_tour'     => array(
503
+					'Event_Categories_Help_Tour',
504
+				),
505
+				'metaboxes'     => $this->_default_espresso_metaboxes,
506
+				'require_nonce' => false,
507
+			),
508
+		);
509
+	}
510
+
511
+
512
+	/**
513
+	 * Used to register any global screen options if necessary for every route in this admin page group.
514
+	 */
515
+	protected function _add_screen_options()
516
+	{
517
+	}
518
+
519
+
520
+	/**
521
+	 * Implementing the screen options for the 'default' route.
522
+	 */
523
+	protected function _add_screen_options_default()
524
+	{
525
+		$this->_per_page_screen_option();
526
+	}
527
+
528
+
529
+	/**
530
+	 * Implementing screen options for the category list route.
531
+	 */
532
+	protected function _add_screen_options_category_list()
533
+	{
534
+		$page_title = $this->_admin_page_title;
535
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
536
+		$this->_per_page_screen_option();
537
+		$this->_admin_page_title = $page_title;
538
+	}
539
+
540
+
541
+	/**
542
+	 * Used to register any global feature pointers for the admin page group.
543
+	 */
544
+	protected function _add_feature_pointers()
545
+	{
546
+	}
547
+
548
+
549
+	/**
550
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
551
+	 */
552
+	public function load_scripts_styles()
553
+	{
554
+		wp_register_style(
555
+			'events-admin-css',
556
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
557
+			array(),
558
+			EVENT_ESPRESSO_VERSION
559
+		);
560
+		wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
561
+		wp_enqueue_style('events-admin-css');
562
+		wp_enqueue_style('ee-cat-admin');
563
+		//todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
564
+		//registers for all views
565
+		//scripts
566
+		wp_register_script(
567
+			'event_editor_js',
568
+			EVENTS_ASSETS_URL . 'event_editor.js',
569
+			array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
570
+			EVENT_ESPRESSO_VERSION,
571
+			true
572
+		);
573
+	}
574
+
575
+
576
+
577
+	/**
578
+	 * Enqueuing scripts and styles specific to this view
579
+	 */
580
+	public function load_scripts_styles_create_new()
581
+	{
582
+		$this->load_scripts_styles_edit();
583
+	}
584
+
585
+
586
+
587
+	/**
588
+	 * Enqueuing scripts and styles specific to this view
589
+	 */
590
+	public function load_scripts_styles_edit()
591
+	{
592
+		//styles
593
+		wp_enqueue_style('espresso-ui-theme');
594
+		wp_register_style(
595
+			'event-editor-css',
596
+			EVENTS_ASSETS_URL . 'event-editor.css',
597
+			array('ee-admin-css'),
598
+			EVENT_ESPRESSO_VERSION
599
+		);
600
+		wp_enqueue_style('event-editor-css');
601
+		//scripts
602
+		wp_register_script(
603
+			'event-datetime-metabox',
604
+			EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
605
+			array('event_editor_js', 'ee-datepicker'),
606
+			EVENT_ESPRESSO_VERSION
607
+		);
608
+		wp_enqueue_script('event-datetime-metabox');
609
+	}
610
+
611
+
612
+	/**
613
+	 * Populating the _views property for the category list table view.
614
+	 */
615
+	protected function _set_list_table_views_category_list()
616
+	{
617
+		$this->_views = array(
618
+			'all' => array(
619
+				'slug'        => 'all',
620
+				'label'       => esc_html__('All', 'event_espresso'),
621
+				'count'       => 0,
622
+				'bulk_action' => array(
623
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
624
+				),
625
+			),
626
+		);
627
+	}
628
+
629
+
630
+	/**
631
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
632
+	 */
633
+	public function admin_init()
634
+	{
635
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
636
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
637
+			'event_espresso'
638
+		);
639
+	}
640
+
641
+
642
+	/**
643
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page group.
644
+	 */
645
+	public function admin_notices()
646
+	{
647
+	}
648
+
649
+
650
+	/**
651
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
652
+	 * this admin page group.
653
+	 */
654
+	public function admin_footer_scripts()
655
+	{
656
+	}
657
+
658
+
659
+
660
+	/**
661
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
662
+	 * warning (via EE_Error::add_error());
663
+	 *
664
+	 * @param  EE_Event $event Event object
665
+	 * @param string    $req_type
666
+	 * @return void
667
+	 * @throws EE_Error
668
+	 * @access public
669
+	 */
670
+	public function verify_event_edit($event = null, $req_type = '')
671
+	{
672
+		// don't need to do this when processing
673
+		if(!empty($req_type)) {
674
+			return;
675
+		}
676
+		// no event?
677
+		if (empty($event)) {
678
+			// set event
679
+			$event = $this->_cpt_model_obj;
680
+		}
681
+		// STILL no event?
682
+		if (! $event instanceof EE_Event) {
683
+			return;
684
+		}
685
+		$orig_status = $event->status();
686
+		// first check if event is active.
687
+		if (
688
+			$orig_status === EEM_Event::cancelled
689
+			|| $orig_status === EEM_Event::postponed
690
+			|| $event->is_expired()
691
+			|| $event->is_inactive()
692
+		) {
693
+			return;
694
+		}
695
+		//made it here so it IS active... next check that any of the tickets are sold.
696
+		if ($event->is_sold_out(true)) {
697
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
698
+				EE_Error::add_attention(
699
+					sprintf(
700
+						esc_html__(
701
+							'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
702
+							'event_espresso'
703
+						),
704
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
705
+					)
706
+				);
707
+			}
708
+			return;
709
+		} else if ($orig_status === EEM_Event::sold_out) {
710
+			EE_Error::add_attention(
711
+				sprintf(
712
+					esc_html__(
713
+						'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
714
+						'event_espresso'
715
+					),
716
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
717
+				)
718
+			);
719
+		}
720
+		//now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
721
+		if ( ! $event->tickets_on_sale()) {
722
+			return;
723
+		}
724
+		//made it here so show warning
725
+		$this->_edit_event_warning();
726
+	}
727
+
728
+
729
+
730
+	/**
731
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
732
+	 * When needed, hook this into a EE_Error::add_error() notice.
733
+	 *
734
+	 * @access protected
735
+	 * @return void
736
+	 */
737
+	protected function _edit_event_warning()
738
+	{
739
+		// we don't want to add warnings during these requests
740
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'editpost') {
741
+			return;
742
+		}
743
+		EE_Error::add_attention(
744
+			esc_html__(
745
+				'Please be advised that this event has been published and is open for registrations on your website. If you update any registration-related details (i.e. custom questions, messages, tickets, datetimes, etc.) while a registration is in process, the registration process could be interrupted and result in errors for the person registering and potentially incorrect registration or transaction data inside Event Espresso. We recommend editing events during a period of slow traffic, or even temporarily changing the status of an event to "Draft" until your edits are complete.',
746
+				'event_espresso'
747
+			)
748
+		);
749
+	}
750
+
751
+
752
+
753
+	/**
754
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
755
+	 * Otherwise, do the normal logic
756
+	 *
757
+	 * @return string
758
+	 * @throws \EE_Error
759
+	 */
760
+	protected function _create_new_cpt_item()
761
+	{
762
+		$has_timezone_string = get_option('timezone_string');
763
+		//only nag them about setting their timezone if it's their first event, and they haven't already done it
764
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
765
+			EE_Error::add_attention(
766
+				sprintf(
767
+					__(
768
+						'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
769
+						'event_espresso'
770
+					),
771
+					'<br>',
772
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
773
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
774
+					. '</select>',
775
+					'<button class="button button-secondary timezone-submit">',
776
+					'</button><span class="spinner"></span>'
777
+				),
778
+				__FILE__,
779
+				__FUNCTION__,
780
+				__LINE__
781
+			);
782
+		}
783
+		return parent::_create_new_cpt_item();
784
+	}
785
+
786
+
787
+	/**
788
+	 * Sets the _views property for the default route in this admin page group.
789
+	 */
790
+	protected function _set_list_table_views_default()
791
+	{
792
+		$this->_views = array(
793
+			'all'   => array(
794
+				'slug'        => 'all',
795
+				'label'       => esc_html__('View All Events', 'event_espresso'),
796
+				'count'       => 0,
797
+				'bulk_action' => array(
798
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
799
+				),
800
+			),
801
+			'draft' => array(
802
+				'slug'        => 'draft',
803
+				'label'       => esc_html__('Draft', 'event_espresso'),
804
+				'count'       => 0,
805
+				'bulk_action' => array(
806
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
807
+				),
808
+			),
809
+		);
810
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
811
+			$this->_views['trash'] = array(
812
+				'slug'        => 'trash',
813
+				'label'       => esc_html__('Trash', 'event_espresso'),
814
+				'count'       => 0,
815
+				'bulk_action' => array(
816
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
817
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
818
+				),
819
+			);
820
+		}
821
+	}
822
+
823
+
824
+
825
+	/**
826
+	 * Provides the legend item array for the default list table view.
827
+	 * @return array
828
+	 */
829
+	protected function _event_legend_items()
830
+	{
831
+		$items = array(
832
+			'view_details'   => array(
833
+				'class' => 'dashicons dashicons-search',
834
+				'desc'  => esc_html__('View Event', 'event_espresso'),
835
+			),
836
+			'edit_event'     => array(
837
+				'class' => 'ee-icon ee-icon-calendar-edit',
838
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
839
+			),
840
+			'view_attendees' => array(
841
+				'class' => 'dashicons dashicons-groups',
842
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
843
+			),
844
+		);
845
+		$items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
846
+		$statuses = array(
847
+			'sold_out_status'  => array(
848
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
849
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
850
+			),
851
+			'active_status'    => array(
852
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
853
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
854
+			),
855
+			'upcoming_status'  => array(
856
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
857
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
858
+			),
859
+			'postponed_status' => array(
860
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
861
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
862
+			),
863
+			'cancelled_status' => array(
864
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
865
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
866
+			),
867
+			'expired_status'   => array(
868
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
869
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
870
+			),
871
+			'inactive_status'  => array(
872
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
873
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
874
+			),
875
+		);
876
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
877
+		return array_merge($items, $statuses);
878
+	}
879
+
880
+
881
+
882
+	/**
883
+	 * @return EEM_Event
884
+	 */
885
+	private function _event_model()
886
+	{
887
+		if ( ! $this->_event_model instanceof EEM_Event) {
888
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
889
+		}
890
+		return $this->_event_model;
891
+	}
892
+
893
+
894
+
895
+	/**
896
+	 * Adds extra buttons to the WP CPT permalink field row.
897
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
898
+	 *
899
+	 * @param  string $return    the current html
900
+	 * @param  int    $id        the post id for the page
901
+	 * @param  string $new_title What the title is
902
+	 * @param  string $new_slug  what the slug is
903
+	 * @return string            The new html string for the permalink area
904
+	 */
905
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
906
+	{
907
+		//make sure this is only when editing
908
+		if ( ! empty($id)) {
909
+			$post = get_post($id);
910
+			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
911
+					   . esc_html__('Shortcode', 'event_espresso')
912
+					   . '</a> ';
913
+			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
914
+					   . $post->ID
915
+					   . ']">';
916
+		}
917
+		return $return;
918
+	}
919
+
920
+
921
+
922
+	/**
923
+	 * _events_overview_list_table
924
+	 * This contains the logic for showing the events_overview list
925
+	 *
926
+	 * @access protected
927
+	 * @return void
928
+	 * @throws \EE_Error
929
+	 */
930
+	protected function _events_overview_list_table()
931
+	{
932
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
933
+		$this->_template_args['after_list_table'] = ! empty($this->_template_args['after_list_table'])
934
+			? (array)$this->_template_args['after_list_table']
935
+			: array();
936
+		$this->_template_args['after_list_table']['view_event_list_button'] = EEH_HTML::br()
937
+																			  . EEH_Template::get_button_or_link(
938
+				get_post_type_archive_link('espresso_events'),
939
+				esc_html__("View Event Archive Page", "event_espresso"),
940
+				'button'
941
+			);
942
+		$this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
943
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
944
+				'create_new',
945
+				'add',
946
+				array(),
947
+				'add-new-h2'
948
+			);
949
+		$this->display_admin_list_table_page_with_no_sidebar();
950
+	}
951
+
952
+
953
+
954
+	/**
955
+	 * this allows for extra misc actions in the default WP publish box
956
+	 *
957
+	 * @return void
958
+	 */
959
+	public function extra_misc_actions_publish_box()
960
+	{
961
+		$this->_generate_publish_box_extra_content();
962
+	}
963
+
964
+
965
+
966
+	/**
967
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been saved.
968
+	 * Typically you would use this to save any additional data.
969
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
970
+	 * ALSO very important.  When a post transitions from scheduled to published,
971
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from other meta saves.
972
+	 * So MAKE sure that you handle this accordingly.
973
+	 *
974
+	 * @access protected
975
+	 * @abstract
976
+	 * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
977
+	 * @param  object $post    The post object of the cpt that was saved.
978
+	 * @return void
979
+	 * @throws \EE_Error
980
+	 */
981
+	protected function _insert_update_cpt_item($post_id, $post)
982
+	{
983
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
984
+			//get out we're not processing an event save.
985
+			return;
986
+		}
987
+		$event_values = array(
988
+			'EVT_display_desc'                => ! empty($this->_req_data['display_desc']) ? 1 : 0,
989
+			'EVT_display_ticket_selector'     => ! empty($this->_req_data['display_ticket_selector']) ? 1 : 0,
990
+			'EVT_additional_limit'            => min(
991
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
992
+				! empty($this->_req_data['additional_limit']) ? $this->_req_data['additional_limit'] : null
993
+			),
994
+			'EVT_default_registration_status' => ! empty($this->_req_data['EVT_default_registration_status'])
995
+				? $this->_req_data['EVT_default_registration_status']
996
+				: EE_Registry::instance()->CFG->registration->default_STS_ID,
997
+			'EVT_member_only'                 => ! empty($this->_req_data['member_only']) ? 1 : 0,
998
+			'EVT_allow_overflow'              => ! empty($this->_req_data['EVT_allow_overflow']) ? 1 : 0,
999
+			'EVT_timezone_string'             => ! empty($this->_req_data['timezone_string'])
1000
+				? $this->_req_data['timezone_string'] : null,
1001
+			'EVT_external_URL'                => ! empty($this->_req_data['externalURL'])
1002
+				? $this->_req_data['externalURL'] : null,
1003
+			'EVT_phone'                       => ! empty($this->_req_data['event_phone'])
1004
+				? $this->_req_data['event_phone'] : null,
1005
+		);
1006
+		//update event
1007
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1008
+		//get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
1009
+		$get_one_where = array(
1010
+			$this->_event_model()->primary_key_name() => $post_id,
1011
+			'OR' => array(
1012
+				'status' => $post->post_status,
1013
+				// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1014
+				// but the returned object here has a status of "publish", so use the original post status as well
1015
+				'status*1' => $this->_req_data['original_post_status'],
1016
+			)
1017
+		);
1018
+		$event = $this->_event_model()->get_one(array($get_one_where));
1019
+		//the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
1020
+		$event_update_callbacks = apply_filters(
1021
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1022
+			array(
1023
+				array($this, '_default_venue_update'),
1024
+				array($this, '_default_tickets_update')
1025
+			)
1026
+		);
1027
+		$att_success = true;
1028
+		foreach ($event_update_callbacks as $e_callback) {
1029
+			$_success = is_callable($e_callback)
1030
+				? call_user_func($e_callback, $event, $this->_req_data)
1031
+				: false;
1032
+			//if ANY of these updates fail then we want the appropriate global error message
1033
+			$att_success = ! $att_success ? $att_success : $_success;
1034
+		}
1035
+		//any errors?
1036
+		if ($success && false === $att_success) {
1037
+			EE_Error::add_error(
1038
+				esc_html__(
1039
+					'Event Details saved successfully but something went wrong with saving attachments.',
1040
+					'event_espresso'
1041
+				),
1042
+				__FILE__,
1043
+				__FUNCTION__,
1044
+				__LINE__
1045
+			);
1046
+		} else if ($success === false) {
1047
+			EE_Error::add_error(
1048
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1049
+				__FILE__,
1050
+				__FUNCTION__,
1051
+				__LINE__
1052
+			);
1053
+		}
1054
+	}
1055
+
1056
+
1057
+
1058
+	/**
1059
+	 * @see parent::restore_item()
1060
+	 * @param int $post_id
1061
+	 * @param int $revision_id
1062
+	 */
1063
+	protected function _restore_cpt_item($post_id, $revision_id)
1064
+	{
1065
+		//copy existing event meta to new post
1066
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1067
+		if ($post_evt instanceof EE_Event) {
1068
+			//meta revision restore
1069
+			$post_evt->restore_revision($revision_id);
1070
+			//related objs restore
1071
+			$post_evt->restore_revision($revision_id, array('Venue', 'Datetime', 'Price'));
1072
+		}
1073
+	}
1074
+
1075
+
1076
+
1077
+	/**
1078
+	 * Attach the venue to the Event
1079
+	 *
1080
+	 * @param  \EE_Event $evtobj Event Object to add the venue to
1081
+	 * @param  array     $data   The request data from the form
1082
+	 * @return bool           Success or fail.
1083
+	 */
1084
+	protected function _default_venue_update(\EE_Event $evtobj, $data)
1085
+	{
1086
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1087
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1088
+		$rows_affected = null;
1089
+		$venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1090
+		// very important.  If we don't have a venue name...
1091
+		// then we'll get out because not necessary to create empty venue
1092
+		if (empty($data['venue_title'])) {
1093
+			return false;
1094
+		}
1095
+		$venue_array = array(
1096
+			'VNU_wp_user'         => $evtobj->get('EVT_wp_user'),
1097
+			'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1098
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1099
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1100
+			'VNU_short_desc'      => ! empty($data['venue_short_description']) ? $data['venue_short_description']
1101
+				: null,
1102
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1103
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1104
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1105
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1106
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1107
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1108
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1109
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1110
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1111
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1112
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1113
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1114
+			'status'              => 'publish',
1115
+		);
1116
+		//if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1117
+		if ( ! empty($venue_id)) {
1118
+			$update_where = array($venue_model->primary_key_name() => $venue_id);
1119
+			$rows_affected = $venue_model->update($venue_array, array($update_where));
1120
+			//we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
1121
+			$evtobj->_add_relation_to($venue_id, 'Venue');
1122
+			return $rows_affected > 0 ? true : false;
1123
+		} else {
1124
+			//we insert the venue
1125
+			$venue_id = $venue_model->insert($venue_array);
1126
+			$evtobj->_add_relation_to($venue_id, 'Venue');
1127
+			return ! empty($venue_id) ? true : false;
1128
+		}
1129
+		//when we have the ancestor come in it's already been handled by the revision save.
1130
+	}
1131
+
1132
+
1133
+
1134
+	/**
1135
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1136
+	 *
1137
+	 * @param  EE_Event $evtobj The Event object we're attaching data to
1138
+	 * @param  array    $data   The request data from the form
1139
+	 * @return array
1140
+	 */
1141
+	protected function _default_tickets_update(EE_Event $evtobj, $data)
1142
+	{
1143
+		$success = true;
1144
+		$saved_dtt = null;
1145
+		$saved_tickets = array();
1146
+		$incoming_date_formats = array('Y-m-d', 'h:i a');
1147
+		foreach ($data['edit_event_datetimes'] as $row => $dtt) {
1148
+			//trim all values to ensure any excess whitespace is removed.
1149
+			$dtt = array_map('trim', $dtt);
1150
+			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end']
1151
+				: $dtt['DTT_EVT_start'];
1152
+			$datetime_values = array(
1153
+				'DTT_ID'        => ! empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : null,
1154
+				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
1155
+				'DTT_EVT_end'   => $dtt['DTT_EVT_end'],
1156
+				'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'],
1157
+				'DTT_order'     => $row,
1158
+			);
1159
+			//if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1160
+			if ( ! empty($dtt['DTT_ID'])) {
1161
+				$DTM = EE_Registry::instance()
1162
+								  ->load_model('Datetime', array($evtobj->get_timezone()))
1163
+								  ->get_one_by_ID($dtt['DTT_ID']);
1164
+				$DTM->set_date_format($incoming_date_formats[0]);
1165
+				$DTM->set_time_format($incoming_date_formats[1]);
1166
+				foreach ($datetime_values as $field => $value) {
1167
+					$DTM->set($field, $value);
1168
+				}
1169
+				//make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1170
+				$saved_dtts[$DTM->ID()] = $DTM;
1171
+			} else {
1172
+				$DTM = EE_Registry::instance()->load_class(
1173
+					'Datetime',
1174
+					array($datetime_values, $evtobj->get_timezone(), $incoming_date_formats),
1175
+					false,
1176
+					false
1177
+				);
1178
+				foreach ($datetime_values as $field => $value) {
1179
+					$DTM->set($field, $value);
1180
+				}
1181
+			}
1182
+			$DTM->save();
1183
+			$DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
1184
+			//load DTT helper
1185
+			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1186
+			if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
1187
+				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
1188
+				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1189
+				$DTT->save();
1190
+			}
1191
+			//now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
1192
+			$saved_dtt = $DTT;
1193
+			$success = ! $success ? $success : $DTT;
1194
+			//if ANY of these updates fail then we want the appropriate global error message.
1195
+			// //todo this is actually sucky we need a better error message but this is what it is for now.
1196
+		}
1197
+		//no dtts get deleted so we don't do any of that logic here.
1198
+		//update tickets next
1199
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
1200
+		foreach ($data['edit_tickets'] as $row => $tkt) {
1201
+			$incoming_date_formats = array('Y-m-d', 'h:i a');
1202
+			$update_prices = false;
1203
+			$ticket_price = isset($data['edit_prices'][$row][1]['PRC_amount'])
1204
+				? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1205
+			// trim inputs to ensure any excess whitespace is removed.
1206
+			$tkt = array_map('trim', $tkt);
1207
+			if (empty($tkt['TKT_start_date'])) {
1208
+				//let's use now in the set timezone.
1209
+				$now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1210
+				$tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1211
+			}
1212
+			if (empty($tkt['TKT_end_date'])) {
1213
+				//use the start date of the first datetime
1214
+				$dtt = $evtobj->first_datetime();
1215
+				$tkt['TKT_end_date'] = $dtt->start_date_and_time(
1216
+					$incoming_date_formats[0],
1217
+					$incoming_date_formats[1]
1218
+				);
1219
+			}
1220
+			$TKT_values = array(
1221
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
1222
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
1223
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
1224
+				'TKT_description' => ! empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '',
1225
+				'TKT_start_date'  => $tkt['TKT_start_date'],
1226
+				'TKT_end_date'    => $tkt['TKT_end_date'],
1227
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'],
1228
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'],
1229
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
1230
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
1231
+				'TKT_row'         => $row,
1232
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row,
1233
+				'TKT_price'       => $ticket_price,
1234
+			);
1235
+			//if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1236
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
1237
+				$TKT_values['TKT_ID'] = 0;
1238
+				$TKT_values['TKT_is_default'] = 0;
1239
+				$TKT_values['TKT_price'] = $ticket_price;
1240
+				$update_prices = true;
1241
+			}
1242
+			//if we have a TKT_ID then we need to get that existing TKT_obj and update it
1243
+			//we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1244
+			//keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1245
+			if ( ! empty($tkt['TKT_ID'])) {
1246
+				$TKT = EE_Registry::instance()
1247
+								  ->load_model('Ticket', array($evtobj->get_timezone()))
1248
+								  ->get_one_by_ID($tkt['TKT_ID']);
1249
+				if ($TKT instanceof EE_Ticket) {
1250
+					$ticket_sold = $TKT->count_related(
1251
+						'Registration',
1252
+						array(
1253
+							array(
1254
+								'STS_ID' => array(
1255
+									'NOT IN',
1256
+									array(EEM_Registration::status_id_incomplete),
1257
+								),
1258
+							),
1259
+						)
1260
+					) > 0 ? true : false;
1261
+					//let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1262
+					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price')
1263
+									  && ! $TKT->get(
1264
+						'TKT_deleted'
1265
+					) ? true : false;
1266
+					$TKT->set_date_format($incoming_date_formats[0]);
1267
+					$TKT->set_time_format($incoming_date_formats[1]);
1268
+					//set new values
1269
+					foreach ($TKT_values as $field => $value) {
1270
+						if ($field == 'TKT_qty') {
1271
+							$TKT->set_qty($value);
1272
+						} else {
1273
+							$TKT->set($field, $value);
1274
+						}
1275
+					}
1276
+					//if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1277
+					if ($create_new_TKT) {
1278
+						//archive the old ticket first
1279
+						$TKT->set('TKT_deleted', 1);
1280
+						$TKT->save();
1281
+						//make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1282
+						$saved_tickets[$TKT->ID()] = $TKT;
1283
+						//create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1284
+						$TKT = clone $TKT;
1285
+						$TKT->set('TKT_ID', 0);
1286
+						$TKT->set('TKT_deleted', 0);
1287
+						$TKT->set('TKT_price', $ticket_price);
1288
+						$TKT->set('TKT_sold', 0);
1289
+						//now we need to make sure that $new prices are created as well and attached to new ticket.
1290
+						$update_prices = true;
1291
+					}
1292
+					//make sure price is set if it hasn't been already
1293
+					$TKT->set('TKT_price', $ticket_price);
1294
+				}
1295
+			} else {
1296
+				//no TKT_id so a new TKT
1297
+				$TKT_values['TKT_price'] = $ticket_price;
1298
+				$TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), false, false);
1299
+				if ($TKT instanceof EE_Ticket) {
1300
+					//need to reset values to properly account for the date formats
1301
+					$TKT->set_date_format($incoming_date_formats[0]);
1302
+					$TKT->set_time_format($incoming_date_formats[1]);
1303
+					$TKT->set_timezone($evtobj->get_timezone());
1304
+					//set new values
1305
+					foreach ($TKT_values as $field => $value) {
1306
+						if ($field == 'TKT_qty') {
1307
+							$TKT->set_qty($value);
1308
+						} else {
1309
+							$TKT->set($field, $value);
1310
+						}
1311
+					}
1312
+					$update_prices = true;
1313
+				}
1314
+			}
1315
+			// cap ticket qty by datetime reg limits
1316
+			$TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
1317
+			//update ticket.
1318
+			$TKT->save();
1319
+			//before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1320
+			if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
1321
+				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
1322
+				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1323
+				$TKT->save();
1324
+			}
1325
+			//initially let's add the ticket to the dtt
1326
+			$saved_dtt->_add_relation_to($TKT, 'Ticket');
1327
+			$saved_tickets[$TKT->ID()] = $TKT;
1328
+			//add prices to ticket
1329
+			$this->_add_prices_to_ticket($data['edit_prices'][$row], $TKT, $update_prices);
1330
+		}
1331
+		//however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1332
+		$old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
1333
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1334
+		foreach ($tickets_removed as $id) {
1335
+			$id = absint($id);
1336
+			//get the ticket for this id
1337
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1338
+			//need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1339
+			$dtts = $tkt_to_remove->get_many_related('Datetime');
1340
+			foreach ($dtts as $dtt) {
1341
+				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1342
+			}
1343
+			//need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1344
+			$tkt_to_remove->delete_related_permanently('Price');
1345
+			//finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1346
+			$tkt_to_remove->delete_permanently();
1347
+		}
1348
+		return array($saved_dtt, $saved_tickets);
1349
+	}
1350
+
1351
+
1352
+
1353
+	/**
1354
+	 * This attaches a list of given prices to a ticket.
1355
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
1356
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
1357
+	 * price info and prices are automatically "archived" via the ticket.
1358
+	 *
1359
+	 * @access  private
1360
+	 * @param array     $prices     Array of prices from the form.
1361
+	 * @param EE_Ticket $ticket     EE_Ticket object that prices are being attached to.
1362
+	 * @param bool      $new_prices Whether attach existing incoming prices or create new ones.
1363
+	 * @return  void
1364
+	 */
1365
+	private function _add_prices_to_ticket($prices, EE_Ticket $ticket, $new_prices = false)
1366
+	{
1367
+		foreach ($prices as $row => $prc) {
1368
+			$PRC_values = array(
1369
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
1370
+				'PRT_ID'         => ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null,
1371
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
1372
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
1373
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
1374
+				'PRC_is_default' => 0, //make sure prices are NOT set as default from this context
1375
+				'PRC_order'      => $row,
1376
+			);
1377
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
1378
+				$PRC_values['PRC_ID'] = 0;
1379
+				$PRC = EE_Registry::instance()->load_class('Price', array($PRC_values), false, false);
1380
+			} else {
1381
+				$PRC = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
1382
+				//update this price with new values
1383
+				foreach ($PRC_values as $field => $newprc) {
1384
+					$PRC->set($field, $newprc);
1385
+				}
1386
+				$PRC->save();
1387
+			}
1388
+			$ticket->_add_relation_to($PRC, 'Price');
1389
+		}
1390
+	}
1391
+
1392
+
1393
+
1394
+	/**
1395
+	 * Add in our autosave ajax handlers
1396
+	 *
1397
+	 */
1398
+	protected function _ee_autosave_create_new()
1399
+	{
1400
+	}
1401
+
1402
+
1403
+	/**
1404
+	 * More autosave handlers.
1405
+	 */
1406
+	protected function _ee_autosave_edit()
1407
+	{
1408
+		return; //TEMPORARILY EXITING CAUSE THIS IS A TODO
1409
+	}
1410
+
1411
+
1412
+
1413
+	/**
1414
+	 *    _generate_publish_box_extra_content
1415
+	 */
1416
+	private function _generate_publish_box_extra_content()
1417
+	{
1418
+		//load formatter helper
1419
+		//args for getting related registrations
1420
+		$approved_query_args = array(
1421
+			array(
1422
+				'REG_deleted' => 0,
1423
+				'STS_ID'      => EEM_Registration::status_id_approved,
1424
+			),
1425
+		);
1426
+		$not_approved_query_args = array(
1427
+			array(
1428
+				'REG_deleted' => 0,
1429
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1430
+			),
1431
+		);
1432
+		$pending_payment_query_args = array(
1433
+			array(
1434
+				'REG_deleted' => 0,
1435
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1436
+			),
1437
+		);
1438
+		// publish box
1439
+		$publish_box_extra_args = array(
1440
+			'view_approved_reg_url'        => add_query_arg(
1441
+				array(
1442
+					'action'      => 'default',
1443
+					'event_id'    => $this->_cpt_model_obj->ID(),
1444
+					'_reg_status' => EEM_Registration::status_id_approved,
1445
+				),
1446
+				REG_ADMIN_URL
1447
+			),
1448
+			'view_not_approved_reg_url'    => add_query_arg(
1449
+				array(
1450
+					'action'      => 'default',
1451
+					'event_id'    => $this->_cpt_model_obj->ID(),
1452
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1453
+				),
1454
+				REG_ADMIN_URL
1455
+			),
1456
+			'view_pending_payment_reg_url' => add_query_arg(
1457
+				array(
1458
+					'action'      => 'default',
1459
+					'event_id'    => $this->_cpt_model_obj->ID(),
1460
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1461
+				),
1462
+				REG_ADMIN_URL
1463
+			),
1464
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1465
+				'Registration',
1466
+				$approved_query_args
1467
+			),
1468
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1469
+				'Registration',
1470
+				$not_approved_query_args
1471
+			),
1472
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1473
+				'Registration',
1474
+				$pending_payment_query_args
1475
+			),
1476
+			'misc_pub_section_class'       => apply_filters(
1477
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1478
+				'misc-pub-section'
1479
+			),
1480
+		);
1481
+		ob_start();
1482
+		do_action(
1483
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1484
+			$this->_cpt_model_obj
1485
+		);
1486
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1487
+		// load template
1488
+		EEH_Template::display_template(
1489
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1490
+			$publish_box_extra_args
1491
+		);
1492
+	}
1493
+
1494
+
1495
+
1496
+	/**
1497
+	 * @return EE_Event
1498
+	 */
1499
+	public function get_event_object()
1500
+	{
1501
+		return $this->_cpt_model_obj;
1502
+	}
1503
+
1504
+
1505
+
1506
+
1507
+	/** METABOXES * */
1508
+	/**
1509
+	 * _register_event_editor_meta_boxes
1510
+	 * add all metaboxes related to the event_editor
1511
+	 *
1512
+	 * @return void
1513
+	 */
1514
+	protected function _register_event_editor_meta_boxes()
1515
+	{
1516
+		$this->verify_cpt_object();
1517
+		add_meta_box(
1518
+			'espresso_event_editor_tickets',
1519
+			esc_html__('Event Datetime & Ticket', 'event_espresso'),
1520
+			array($this, 'ticket_metabox'),
1521
+			$this->page_slug,
1522
+			'normal',
1523
+			'high'
1524
+		);
1525
+		add_meta_box(
1526
+			'espresso_event_editor_event_options',
1527
+			esc_html__('Event Registration Options', 'event_espresso'),
1528
+			array($this, 'registration_options_meta_box'),
1529
+			$this->page_slug,
1530
+			'side',
1531
+			'default'
1532
+		);
1533
+		// NOTE: if you're looking for other metaboxes in here,
1534
+		// where a metabox has a related management page in the admin
1535
+		// you will find it setup in the related management page's "_Hooks" file.
1536
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1537
+	}
1538
+
1539
+
1540
+	/**
1541
+	 * @throws DomainException
1542
+	 * @throws EE_Error
1543
+	 */
1544
+	public function ticket_metabox()
1545
+	{
1546
+		$existing_datetime_ids = $existing_ticket_ids = array();
1547
+		//defaults for template args
1548
+		$template_args = array(
1549
+			'existing_datetime_ids'    => '',
1550
+			'event_datetime_help_link' => '',
1551
+			'ticket_options_help_link' => '',
1552
+			'time'                     => null,
1553
+			'ticket_rows'              => '',
1554
+			'existing_ticket_ids'      => '',
1555
+			'total_ticket_rows'        => 1,
1556
+			'ticket_js_structure'      => '',
1557
+			'trash_icon'               => 'ee-lock-icon',
1558
+			'disabled'                 => '',
1559
+		);
1560
+		$event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1561
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1562
+		/**
1563
+		 * 1. Start with retrieving Datetimes
1564
+		 * 2. Fore each datetime get related tickets
1565
+		 * 3. For each ticket get related prices
1566
+		 */
1567
+		$times = EE_Registry::instance()->load_model('Datetime')->get_all_event_dates($event_id);
1568
+		/** @type EE_Datetime $first_datetime */
1569
+		$first_datetime = reset($times);
1570
+		//do we get related tickets?
1571
+		if ($first_datetime instanceof EE_Datetime
1572
+			&& $first_datetime->ID() !== 0
1573
+		) {
1574
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1575
+			$template_args['time'] = $first_datetime;
1576
+			$related_tickets = $first_datetime->tickets(
1577
+				array(
1578
+					array('OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0)),
1579
+					'default_where_conditions' => 'none',
1580
+				)
1581
+			);
1582
+			if ( ! empty($related_tickets)) {
1583
+				$template_args['total_ticket_rows'] = count($related_tickets);
1584
+				$row = 0;
1585
+				foreach ($related_tickets as $ticket) {
1586
+					$existing_ticket_ids[] = $ticket->get('TKT_ID');
1587
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1588
+					$row++;
1589
+				}
1590
+			} else {
1591
+				$template_args['total_ticket_rows'] = 1;
1592
+				/** @type EE_Ticket $ticket */
1593
+				$ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1594
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1595
+			}
1596
+		} else {
1597
+			$template_args['time'] = $times[0];
1598
+			/** @type EE_Ticket $ticket */
1599
+			$ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
1600
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket[1]);
1601
+			// NOTE: we're just sending the first default row
1602
+			// (decaf can't manage default tickets so this should be sufficient);
1603
+		}
1604
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1605
+			'event_editor_event_datetimes_help_tab'
1606
+		);
1607
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1608
+		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1609
+		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1610
+		$template_args['ticket_js_structure'] = $this->_get_ticket_row(
1611
+			EE_Registry::instance()->load_model('Ticket')->create_default_object(),
1612
+			true
1613
+		);
1614
+		$template = apply_filters(
1615
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1616
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1617
+		);
1618
+		EEH_Template::display_template($template, $template_args);
1619
+	}
1620
+
1621
+
1622
+
1623
+	/**
1624
+	 * Setup an individual ticket form for the decaf event editor page
1625
+	 *
1626
+	 * @access private
1627
+	 * @param  EE_Ticket $ticket   the ticket object
1628
+	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1629
+	 * @param int        $row
1630
+	 * @return string generated html for the ticket row.
1631
+	 */
1632
+	private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1633
+	{
1634
+		$template_args = array(
1635
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1636
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1637
+				: '',
1638
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1639
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1640
+			'TKT_name'            => $ticket->get('TKT_name'),
1641
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1642
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1643
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1644
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1645
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1646
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1647
+			'trash_icon'          => ($skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')))
1648
+									 && ( ! empty($ticket) && $ticket->get('TKT_sold') === 0)
1649
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1650
+			'disabled'            => $skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1651
+				: ' disabled=disabled',
1652
+		);
1653
+		$price = $ticket->ID() !== 0
1654
+			? $ticket->get_first_related('Price', array('default_where_conditions' => 'none'))
1655
+			: EE_Registry::instance()->load_model('Price')->create_default_object();
1656
+		$price_args = array(
1657
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1658
+			'PRC_amount'            => $price->get('PRC_amount'),
1659
+			'PRT_ID'                => $price->get('PRT_ID'),
1660
+			'PRC_ID'                => $price->get('PRC_ID'),
1661
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1662
+		);
1663
+		//make sure we have default start and end dates if skeleton
1664
+		//handle rows that should NOT be empty
1665
+		if (empty($template_args['TKT_start_date'])) {
1666
+			//if empty then the start date will be now.
1667
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1668
+		}
1669
+		if (empty($template_args['TKT_end_date'])) {
1670
+			//get the earliest datetime (if present);
1671
+			$earliest_dtt = $this->_cpt_model_obj->ID() > 0
1672
+				? $this->_cpt_model_obj->get_first_related(
1673
+					'Datetime',
1674
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1675
+				)
1676
+				: null;
1677
+			if ( ! empty($earliest_dtt)) {
1678
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1679
+			} else {
1680
+				$template_args['TKT_end_date'] = date(
1681
+					'Y-m-d h:i a',
1682
+					mktime(0, 0, 0, date("m"), date("d") + 7, date("Y"))
1683
+				);
1684
+			}
1685
+		}
1686
+		$template_args = array_merge($template_args, $price_args);
1687
+		$template = apply_filters(
1688
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1689
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1690
+			$ticket
1691
+		);
1692
+		return EEH_Template::display_template($template, $template_args, true);
1693
+	}
1694
+
1695
+
1696
+	/**
1697
+	 * @throws DomainException
1698
+	 */
1699
+	public function registration_options_meta_box()
1700
+	{
1701
+		$yes_no_values = array(
1702
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
1703
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
1704
+		);
1705
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1706
+			array(
1707
+				EEM_Registration::status_id_cancelled,
1708
+				EEM_Registration::status_id_declined,
1709
+				EEM_Registration::status_id_incomplete,
1710
+			),
1711
+			true
1712
+		);
1713
+		//$template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1714
+		$template_args['_event'] = $this->_cpt_model_obj;
1715
+		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
1716
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
1717
+		$template_args['default_registration_status'] = EEH_Form_Fields::select_input(
1718
+			'default_reg_status',
1719
+			$default_reg_status_values,
1720
+			$this->_cpt_model_obj->default_registration_status()
1721
+		);
1722
+		$template_args['display_description'] = EEH_Form_Fields::select_input(
1723
+			'display_desc',
1724
+			$yes_no_values,
1725
+			$this->_cpt_model_obj->display_description()
1726
+		);
1727
+		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1728
+			'display_ticket_selector',
1729
+			$yes_no_values,
1730
+			$this->_cpt_model_obj->display_ticket_selector(),
1731
+			'',
1732
+			'',
1733
+			false
1734
+		);
1735
+		$template_args['additional_registration_options'] = apply_filters(
1736
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1737
+			'',
1738
+			$template_args,
1739
+			$yes_no_values,
1740
+			$default_reg_status_values
1741
+		);
1742
+		EEH_Template::display_template(
1743
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1744
+			$template_args
1745
+		);
1746
+	}
1747
+
1748
+
1749
+
1750
+	/**
1751
+	 * _get_events()
1752
+	 * This method simply returns all the events (for the given _view and paging)
1753
+	 *
1754
+	 * @access public
1755
+	 * @param int  $per_page     count of items per page (20 default);
1756
+	 * @param int  $current_page what is the current page being viewed.
1757
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1758
+	 *                           If FALSE then we return an array of event objects
1759
+	 *                           that match the given _view and paging parameters.
1760
+	 * @return array an array of event objects.
1761
+	 */
1762
+	public function get_events($per_page = 10, $current_page = 1, $count = false)
1763
+	{
1764
+		$EEME = $this->_event_model();
1765
+		$offset = ($current_page - 1) * $per_page;
1766
+		$limit = $count ? null : $offset . ',' . $per_page;
1767
+		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1768
+		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1769
+		if (isset($this->_req_data['month_range'])) {
1770
+			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1771
+			//simulate the FIRST day of the month, that fixes issues for months like February
1772
+			//where PHP doesn't know what to assume for date.
1773
+			//@see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1774
+			$month_r = ! empty($pieces[0]) ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1775
+			$year_r = ! empty($pieces[1]) ? $pieces[1] : '';
1776
+		}
1777
+		$where = array();
1778
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1779
+		//determine what post_status our condition will have for the query.
1780
+		switch ($status) {
1781
+			case 'month' :
1782
+			case 'today' :
1783
+			case null :
1784
+			case 'all' :
1785
+				break;
1786
+			case 'draft' :
1787
+				$where['status'] = array('IN', array('draft', 'auto-draft'));
1788
+				break;
1789
+			default :
1790
+				$where['status'] = $status;
1791
+		}
1792
+		//categories?
1793
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1794
+			? $this->_req_data['EVT_CAT'] : null;
1795
+		if ( ! empty ($category)) {
1796
+			$where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1797
+			$where['Term_Taxonomy.term_id'] = $category;
1798
+		}
1799
+		//date where conditions
1800
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1801
+		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1802
+			$DateTime = new DateTime(
1803
+				$year_r . '-' . $month_r . '-01 00:00:00',
1804
+				new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1805
+			);
1806
+			$start = $DateTime->format(implode(' ', $start_formats));
1807
+			$end = $DateTime->setDate($year_r, $month_r, $DateTime
1808
+				->format('t'))->setTime(23, 59, 59)
1809
+							->format(implode(' ', $start_formats));
1810
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1811
+		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1812
+			$DateTime = new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1813
+			$start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1814
+			$end = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1815
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1816
+		} else if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'month') {
1817
+			$now = date('Y-m-01');
1818
+			$DateTime = new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1819
+			$start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1820
+			$end = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1821
+							->setTime(23, 59, 59)
1822
+							->format(implode(' ', $start_formats));
1823
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1824
+		}
1825
+		if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1826
+			$where['EVT_wp_user'] = get_current_user_id();
1827
+		} else {
1828
+			if ( ! isset($where['status'])) {
1829
+				if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1830
+					$where['OR'] = array(
1831
+						'status*restrict_private' => array('!=', 'private'),
1832
+						'AND'                     => array(
1833
+							'status*inclusive' => array('=', 'private'),
1834
+							'EVT_wp_user'      => get_current_user_id(),
1835
+						),
1836
+					);
1837
+				}
1838
+			}
1839
+		}
1840
+		if (isset($this->_req_data['EVT_wp_user'])) {
1841
+			if ($this->_req_data['EVT_wp_user'] != get_current_user_id()
1842
+				&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1843
+			) {
1844
+				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1845
+			}
1846
+		}
1847
+		//search query handling
1848
+		if (isset($this->_req_data['s'])) {
1849
+			$search_string = '%' . $this->_req_data['s'] . '%';
1850
+			$where['OR'] = array(
1851
+				'EVT_name'       => array('LIKE', $search_string),
1852
+				'EVT_desc'       => array('LIKE', $search_string),
1853
+				'EVT_short_desc' => array('LIKE', $search_string),
1854
+			);
1855
+		}
1856
+		$where = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data);
1857
+		$query_params = apply_filters(
1858
+			'FHEE__Events_Admin_Page__get_events__query_params',
1859
+			array(
1860
+				$where,
1861
+				'limit'    => $limit,
1862
+				'order_by' => $orderby,
1863
+				'order'    => $order,
1864
+				'group_by' => 'EVT_ID',
1865
+			),
1866
+			$this->_req_data
1867
+		);
1868
+		//let's first check if we have special requests coming in.
1869
+		if (isset($this->_req_data['active_status'])) {
1870
+			switch ($this->_req_data['active_status']) {
1871
+				case 'upcoming' :
1872
+					return $EEME->get_upcoming_events($query_params, $count);
1873
+					break;
1874
+				case 'expired' :
1875
+					return $EEME->get_expired_events($query_params, $count);
1876
+					break;
1877
+				case 'active' :
1878
+					return $EEME->get_active_events($query_params, $count);
1879
+					break;
1880
+				case 'inactive' :
1881
+					return $EEME->get_inactive_events($query_params, $count);
1882
+					break;
1883
+			}
1884
+		}
1885
+		$events = $count ? $EEME->count(array($where), 'EVT_ID', true) : $EEME->get_all($query_params);
1886
+		return $events;
1887
+	}
1888
+
1889
+
1890
+
1891
+	/**
1892
+	 * handling for WordPress CPT actions (trash, restore, delete)
1893
+	 *
1894
+	 * @param string $post_id
1895
+	 */
1896
+	public function trash_cpt_item($post_id)
1897
+	{
1898
+		$this->_req_data['EVT_ID'] = $post_id;
1899
+		$this->_trash_or_restore_event('trash', false);
1900
+	}
1901
+
1902
+
1903
+
1904
+	/**
1905
+	 * @param string $post_id
1906
+	 */
1907
+	public function restore_cpt_item($post_id)
1908
+	{
1909
+		$this->_req_data['EVT_ID'] = $post_id;
1910
+		$this->_trash_or_restore_event('draft', false);
1911
+	}
1912
+
1913
+
1914
+
1915
+	/**
1916
+	 * @param string $post_id
1917
+	 */
1918
+	public function delete_cpt_item($post_id)
1919
+	{
1920
+		$this->_req_data['EVT_ID'] = $post_id;
1921
+		$this->_delete_event(false);
1922
+	}
1923
+
1924
+
1925
+
1926
+	/**
1927
+	 * _trash_or_restore_event
1928
+	 *
1929
+	 * @access protected
1930
+	 * @param  string $event_status
1931
+	 * @param bool    $redirect_after
1932
+	 */
1933
+	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
1934
+	{
1935
+		//determine the event id and set to array.
1936
+		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : false;
1937
+		// loop thru events
1938
+		if ($EVT_ID) {
1939
+			// clean status
1940
+			$event_status = sanitize_key($event_status);
1941
+			// grab status
1942
+			if ( ! empty($event_status)) {
1943
+				$success = $this->_change_event_status($EVT_ID, $event_status);
1944
+			} else {
1945
+				$success = false;
1946
+				$msg = esc_html__(
1947
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1948
+					'event_espresso'
1949
+				);
1950
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1951
+			}
1952
+		} else {
1953
+			$success = false;
1954
+			$msg = esc_html__(
1955
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
1956
+				'event_espresso'
1957
+			);
1958
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1959
+		}
1960
+		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1961
+		if ($redirect_after) {
1962
+			$this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
1963
+		}
1964
+	}
1965
+
1966
+
1967
+
1968
+	/**
1969
+	 * _trash_or_restore_events
1970
+	 *
1971
+	 * @access protected
1972
+	 * @param  string $event_status
1973
+	 * @return void
1974
+	 */
1975
+	protected function _trash_or_restore_events($event_status = 'trash')
1976
+	{
1977
+		// clean status
1978
+		$event_status = sanitize_key($event_status);
1979
+		// grab status
1980
+		if ( ! empty($event_status)) {
1981
+			$success = true;
1982
+			//determine the event id and set to array.
1983
+			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array)$this->_req_data['EVT_IDs'] : array();
1984
+			// loop thru events
1985
+			foreach ($EVT_IDs as $EVT_ID) {
1986
+				if ($EVT_ID = absint($EVT_ID)) {
1987
+					$results = $this->_change_event_status($EVT_ID, $event_status);
1988
+					$success = $results !== false ? $success : false;
1989
+				} else {
1990
+					$msg = sprintf(
1991
+						esc_html__(
1992
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
1993
+							'event_espresso'
1994
+						),
1995
+						$EVT_ID
1996
+					);
1997
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1998
+					$success = false;
1999
+				}
2000
+			}
2001
+		} else {
2002
+			$success = false;
2003
+			$msg = esc_html__(
2004
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2005
+				'event_espresso'
2006
+			);
2007
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2008
+		}
2009
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2010
+		$success = $success ? 2 : false;
2011
+		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
2012
+		$this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
2013
+	}
2014
+
2015
+
2016
+
2017
+	/**
2018
+	 * _trash_or_restore_events
2019
+	 *
2020
+	 * @access  private
2021
+	 * @param  int    $EVT_ID
2022
+	 * @param  string $event_status
2023
+	 * @return bool
2024
+	 */
2025
+	private function _change_event_status($EVT_ID = 0, $event_status = '')
2026
+	{
2027
+		// grab event id
2028
+		if ( ! $EVT_ID) {
2029
+			$msg = esc_html__(
2030
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2031
+				'event_espresso'
2032
+			);
2033
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2034
+			return false;
2035
+		}
2036
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2037
+		// clean status
2038
+		$event_status = sanitize_key($event_status);
2039
+		// grab status
2040
+		if (empty($event_status)) {
2041
+			$msg = esc_html__(
2042
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2043
+				'event_espresso'
2044
+			);
2045
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2046
+			return false;
2047
+		}
2048
+		// was event trashed or restored ?
2049
+		switch ($event_status) {
2050
+			case 'draft' :
2051
+				$action = 'restored from the trash';
2052
+				$hook = 'AHEE_event_restored_from_trash';
2053
+				break;
2054
+			case 'trash' :
2055
+				$action = 'moved to the trash';
2056
+				$hook = 'AHEE_event_moved_to_trash';
2057
+				break;
2058
+			default :
2059
+				$action = 'updated';
2060
+				$hook = false;
2061
+		}
2062
+		//use class to change status
2063
+		$this->_cpt_model_obj->set_status($event_status);
2064
+		$success = $this->_cpt_model_obj->save();
2065
+		if ($success === false) {
2066
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2067
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2068
+			return false;
2069
+		}
2070
+		if ($hook) {
2071
+			do_action($hook);
2072
+		}
2073
+		return true;
2074
+	}
2075
+
2076
+
2077
+
2078
+	/**
2079
+	 * _delete_event
2080
+	 *
2081
+	 * @access protected
2082
+	 * @param bool $redirect_after
2083
+	 */
2084
+	protected function _delete_event($redirect_after = true)
2085
+	{
2086
+		//determine the event id and set to array.
2087
+		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : null;
2088
+		$EVT_ID = isset($this->_req_data['post']) ? absint($this->_req_data['post']) : $EVT_ID;
2089
+		// loop thru events
2090
+		if ($EVT_ID) {
2091
+			$success = $this->_permanently_delete_event($EVT_ID);
2092
+			// get list of events with no prices
2093
+			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2094
+			// remove this event from the list of events with no prices
2095
+			if (isset($espresso_no_ticket_prices[$EVT_ID])) {
2096
+				unset($espresso_no_ticket_prices[$EVT_ID]);
2097
+			}
2098
+			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2099
+		} else {
2100
+			$success = false;
2101
+			$msg = esc_html__(
2102
+				'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2103
+				'event_espresso'
2104
+			);
2105
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2106
+		}
2107
+		if ($redirect_after) {
2108
+			$this->_redirect_after_action(
2109
+				$success,
2110
+				'Event',
2111
+				'deleted',
2112
+				array('action' => 'default', 'status' => 'trash')
2113
+			);
2114
+		}
2115
+	}
2116
+
2117
+
2118
+
2119
+	/**
2120
+	 * _delete_events
2121
+	 *
2122
+	 * @access protected
2123
+	 * @return void
2124
+	 */
2125
+	protected function _delete_events()
2126
+	{
2127
+		$success = true;
2128
+		// get list of events with no prices
2129
+		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2130
+		//determine the event id and set to array.
2131
+		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array)$this->_req_data['EVT_IDs'] : array();
2132
+		// loop thru events
2133
+		foreach ($EVT_IDs as $EVT_ID) {
2134
+			$EVT_ID = absint($EVT_ID);
2135
+			if ($EVT_ID) {
2136
+				$results = $this->_permanently_delete_event($EVT_ID);
2137
+				$success = $results !== false ? $success : false;
2138
+				// remove this event from the list of events with no prices
2139
+				unset($espresso_no_ticket_prices[$EVT_ID]);
2140
+			} else {
2141
+				$success = false;
2142
+				$msg = esc_html__(
2143
+					'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2144
+					'event_espresso'
2145
+				);
2146
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2147
+			}
2148
+		}
2149
+		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2150
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2151
+		$success = $success ? 2 : false;
2152
+		$this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
2153
+	}
2154
+
2155
+
2156
+
2157
+	/**
2158
+	 * _permanently_delete_event
2159
+	 *
2160
+	 * @access  private
2161
+	 * @param  int $EVT_ID
2162
+	 * @return bool
2163
+	 */
2164
+	private function _permanently_delete_event($EVT_ID = 0)
2165
+	{
2166
+		// grab event id
2167
+		if ( ! $EVT_ID) {
2168
+			$msg = esc_html__(
2169
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2170
+				'event_espresso'
2171
+			);
2172
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2173
+			return false;
2174
+		}
2175
+		if (
2176
+			! $this->_cpt_model_obj instanceof EE_Event
2177
+			|| $this->_cpt_model_obj->ID() !== $EVT_ID
2178
+		) {
2179
+			$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2180
+		}
2181
+		if ( ! $this->_cpt_model_obj instanceof EE_Event) {
2182
+			return false;
2183
+		}
2184
+		//need to delete related tickets and prices first.
2185
+		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
2186
+		foreach ($datetimes as $datetime) {
2187
+			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
2188
+			$tickets = $datetime->get_many_related('Ticket');
2189
+			foreach ($tickets as $ticket) {
2190
+				$ticket->_remove_relation_to($datetime, 'Datetime');
2191
+				$ticket->delete_related_permanently('Price');
2192
+				$ticket->delete_permanently();
2193
+			}
2194
+			$datetime->delete();
2195
+		}
2196
+		//what about related venues or terms?
2197
+		$venues = $this->_cpt_model_obj->get_many_related('Venue');
2198
+		foreach ($venues as $venue) {
2199
+			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
2200
+		}
2201
+		//any attached question groups?
2202
+		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2203
+		if ( ! empty($question_groups)) {
2204
+			foreach ($question_groups as $question_group) {
2205
+				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2206
+			}
2207
+		}
2208
+		//Message Template Groups
2209
+		$this->_cpt_model_obj->_remove_relations('Message_Template_Group');
2210
+		/** @type EE_Term_Taxonomy[] $term_taxonomies */
2211
+		$term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
2212
+		foreach ($term_taxonomies as $term_taxonomy) {
2213
+			$this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
2214
+		}
2215
+		$success = $this->_cpt_model_obj->delete_permanently();
2216
+		// did it all go as planned ?
2217
+		if ($success) {
2218
+			$msg = sprintf(esc_html__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2219
+			EE_Error::add_success($msg);
2220
+		} else {
2221
+			$msg = sprintf(
2222
+				esc_html__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'),
2223
+				$EVT_ID
2224
+			);
2225
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
+			return false;
2227
+		}
2228
+		do_action('AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID);
2229
+		return true;
2230
+	}
2231
+
2232
+
2233
+
2234
+	/**
2235
+	 * get total number of events
2236
+	 *
2237
+	 * @access public
2238
+	 * @return int
2239
+	 */
2240
+	public function total_events()
2241
+	{
2242
+		$count = EEM_Event::instance()->count(array('caps' => 'read_admin'), 'EVT_ID', true);
2243
+		return $count;
2244
+	}
2245
+
2246
+
2247
+
2248
+	/**
2249
+	 * get total number of draft events
2250
+	 *
2251
+	 * @access public
2252
+	 * @return int
2253
+	 */
2254
+	public function total_events_draft()
2255
+	{
2256
+		$where = array(
2257
+			'status' => array('IN', array('draft', 'auto-draft')),
2258
+		);
2259
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2260
+		return $count;
2261
+	}
2262
+
2263
+
2264
+
2265
+	/**
2266
+	 * get total number of trashed events
2267
+	 *
2268
+	 * @access public
2269
+	 * @return int
2270
+	 */
2271
+	public function total_trashed_events()
2272
+	{
2273
+		$where = array(
2274
+			'status' => 'trash',
2275
+		);
2276
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2277
+		return $count;
2278
+	}
2279
+
2280
+
2281
+	/**
2282
+	 *    _default_event_settings
2283
+	 *    This generates the Default Settings Tab
2284
+	 *
2285
+	 * @return void
2286
+	 * @throws EE_Error
2287
+	 */
2288
+	protected function _default_event_settings()
2289
+	{
2290
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2291
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
2292
+		$this->_template_args['admin_page_content'] = $this->_default_event_settings_form()->get_html();
2293
+		$this->display_admin_page_with_sidebar();
2294
+	}
2295
+
2296
+
2297
+	/**
2298
+	 * Return the form for event settings.
2299
+	 * @return EE_Form_Section_Proper
2300
+	 */
2301
+	protected function _default_event_settings_form()
2302
+	{
2303
+		$registration_config = EE_Registry::instance()->CFG->registration;
2304
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2305
+		//exclude
2306
+			array(
2307
+				EEM_Registration::status_id_cancelled,
2308
+				EEM_Registration::status_id_declined,
2309
+				EEM_Registration::status_id_incomplete,
2310
+				EEM_Registration::status_id_wait_list,
2311
+			),
2312
+			true
2313
+		);
2314
+		return new EE_Form_Section_Proper(
2315
+			array(
2316
+				'name' => 'update_default_event_settings',
2317
+				'html_id' => 'update_default_event_settings',
2318
+				'html_class' => 'form-table',
2319
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2320
+				'subsections' => apply_filters(
2321
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2322
+					array(
2323
+						'default_reg_status' => new EE_Select_Input(
2324
+							$registration_stati_for_selection,
2325
+							array(
2326
+								'default' => isset($registration_config->default_STS_ID)
2327
+											 && array_key_exists(
2328
+												$registration_config->default_STS_ID,
2329
+												$registration_stati_for_selection
2330
+											 )
2331
+											? sanitize_text_field($registration_config->default_STS_ID)
2332
+											: EEM_Registration::status_id_pending_payment,
2333
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2334
+													. EEH_Template::get_help_tab_link(
2335
+														'default_settings_status_help_tab'
2336
+													),
2337
+								'html_help_text' => esc_html__(
2338
+									'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2339
+									'event_espresso'
2340
+								)
2341
+							)
2342
+						),
2343
+						'default_max_tickets' => new EE_Integer_Input(
2344
+							array(
2345
+								'default' => isset($registration_config->default_maximum_number_of_tickets)
2346
+									? $registration_config->default_maximum_number_of_tickets
2347
+									: EEM_Event::get_default_additional_limit(),
2348
+								'html_label_text' => esc_html__(
2349
+									'Default Maximum Tickets Allowed Per Order:',
2350
+									'event_espresso'
2351
+								) . EEH_Template::get_help_tab_link(
2352
+									'default_maximum_tickets_help_tab"'
2353
+									),
2354
+								'html_help_text' => esc_html__(
2355
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2356
+									'event_espresso'
2357
+								)
2358
+							)
2359
+						)
2360
+					)
2361
+				)
2362
+			)
2363
+		);
2364
+	}
2365
+
2366
+
2367
+	/**
2368
+	 * _update_default_event_settings
2369
+	 *
2370
+	 * @access protected
2371
+	 * @return void
2372
+	 * @throws EE_Error
2373
+	 */
2374
+	protected function _update_default_event_settings()
2375
+	{
2376
+		$registration_config = EE_Registry::instance()->CFG->registration;
2377
+		$form = $this->_default_event_settings_form();
2378
+		if ($form->was_submitted()) {
2379
+			$form->receive_form_submission();
2380
+			if ($form->is_valid()) {
2381
+				$valid_data = $form->valid_data();
2382
+				if (isset($valid_data['default_reg_status'])) {
2383
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2384
+				}
2385
+				if (isset($valid_data['default_max_tickets'])) {
2386
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2387
+				}
2388
+				//update because data was valid!
2389
+				EE_Registry::instance()->CFG->update_espresso_config();
2390
+				EE_Error::overwrite_success();
2391
+				EE_Error::add_success(
2392
+					__('Default Event Settings were updated', 'event_espresso')
2393
+				);
2394
+			}
2395
+		}
2396
+		$this->_redirect_after_action(0, '', '', array('action' => 'default_event_settings'), true);
2397
+	}
2398
+
2399
+
2400
+
2401
+	/*************        Templates        *************/
2402
+	protected function _template_settings()
2403
+	{
2404
+		$this->_admin_page_title = esc_html__('Template Settings (Preview)', 'event_espresso');
2405
+		$this->_template_args['preview_img'] = '<img src="'
2406
+											   . EVENTS_ASSETS_URL
2407
+											   . DS
2408
+											   . 'images'
2409
+											   . DS
2410
+											   . 'caffeinated_template_features.jpg" alt="'
2411
+											   . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2412
+											   . '" />';
2413
+		$this->_template_args['preview_text'] = '<strong>' . esc_html__(
2414
+				'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2415
+				'event_espresso'
2416
+			) . '</strong>';
2417
+		$this->display_admin_caf_preview_page('template_settings_tab');
2418
+	}
2419
+
2420
+
2421
+	/** Event Category Stuff **/
2422
+	/**
2423
+	 * set the _category property with the category object for the loaded page.
2424
+	 *
2425
+	 * @access private
2426
+	 * @return void
2427
+	 */
2428
+	private function _set_category_object()
2429
+	{
2430
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2431
+			return;
2432
+		} //already have the category object so get out.
2433
+		//set default category object
2434
+		$this->_set_empty_category_object();
2435
+		//only set if we've got an id
2436
+		if ( ! isset($this->_req_data['EVT_CAT_ID'])) {
2437
+			return;
2438
+		}
2439
+		$category_id = absint($this->_req_data['EVT_CAT_ID']);
2440
+		$term = get_term($category_id, 'espresso_event_categories');
2441
+		if ( ! empty($term)) {
2442
+			$this->_category->category_name = $term->name;
2443
+			$this->_category->category_identifier = $term->slug;
2444
+			$this->_category->category_desc = $term->description;
2445
+			$this->_category->id = $term->term_id;
2446
+			$this->_category->parent = $term->parent;
2447
+		}
2448
+	}
2449
+
2450
+
2451
+	/**
2452
+	 * Clears out category properties.
2453
+	 */
2454
+	private function _set_empty_category_object()
2455
+	{
2456
+		$this->_category = new stdClass();
2457
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2458
+		$this->_category->id = $this->_category->parent = 0;
2459
+	}
2460
+
2461
+
2462
+	/**
2463
+	 * @throws EE_Error
2464
+	 */
2465
+	protected function _category_list_table()
2466
+	{
2467
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2468
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2469
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2470
+				'add_category',
2471
+				'add_category',
2472
+				array(),
2473
+				'add-new-h2'
2474
+			);
2475
+		$this->display_admin_list_table_page_with_sidebar();
2476
+	}
2477
+
2478
+
2479
+
2480
+	/**
2481
+	 * Output category details view.
2482
+	 */
2483
+	protected function _category_details($view)
2484
+	{
2485
+		//load formatter helper
2486
+		//load field generator helper
2487
+		$route = $view == 'edit' ? 'update_category' : 'insert_category';
2488
+		$this->_set_add_edit_form_tags($route);
2489
+		$this->_set_category_object();
2490
+		$id = ! empty($this->_category->id) ? $this->_category->id : '';
2491
+		$delete_action = 'delete_category';
2492
+		//custom redirect
2493
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2494
+			array('action' => 'category_list'),
2495
+			$this->_admin_base_url
2496
+		);
2497
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2498
+		//take care of contents
2499
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2500
+		$this->display_admin_page_with_sidebar();
2501
+	}
2502
+
2503
+
2504
+
2505
+	/**
2506
+	 * Output category details content.
2507
+	 */
2508
+	protected function _category_details_content()
2509
+	{
2510
+		$editor_args['category_desc'] = array(
2511
+			'type'          => 'wp_editor',
2512
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2513
+			'class'         => 'my_editor_custom',
2514
+			'wpeditor_args' => array('media_buttons' => false),
2515
+		);
2516
+		$_wp_editor = $this->_generate_admin_form_fields($editor_args, 'array');
2517
+		$all_terms = get_terms(
2518
+			array('espresso_event_categories'),
2519
+			array('hide_empty' => 0, 'exclude' => array($this->_category->id))
2520
+		);
2521
+		//setup category select for term parents.
2522
+		$category_select_values[] = array(
2523
+			'text' => esc_html__('No Parent', 'event_espresso'),
2524
+			'id'   => 0,
2525
+		);
2526
+		foreach ($all_terms as $term) {
2527
+			$category_select_values[] = array(
2528
+				'text' => $term->name,
2529
+				'id'   => $term->term_id,
2530
+			);
2531
+		}
2532
+		$category_select = EEH_Form_Fields::select_input(
2533
+			'category_parent',
2534
+			$category_select_values,
2535
+			$this->_category->parent
2536
+		);
2537
+		$template_args = array(
2538
+			'category'                 => $this->_category,
2539
+			'category_select'          => $category_select,
2540
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2541
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2542
+			'disable'                  => '',
2543
+			'disabled_message'         => false,
2544
+		);
2545
+		$template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2546
+		return EEH_Template::display_template($template, $template_args, true);
2547
+	}
2548
+
2549
+
2550
+	/**
2551
+	 * Handles deleting categories.
2552
+	 */
2553
+	protected function _delete_categories()
2554
+	{
2555
+		$cat_ids = isset($this->_req_data['EVT_CAT_ID']) ? (array)$this->_req_data['EVT_CAT_ID']
2556
+			: (array)$this->_req_data['category_id'];
2557
+		foreach ($cat_ids as $cat_id) {
2558
+			$this->_delete_category($cat_id);
2559
+		}
2560
+		//doesn't matter what page we're coming from... we're going to the same place after delete.
2561
+		$query_args = array(
2562
+			'action' => 'category_list',
2563
+		);
2564
+		$this->_redirect_after_action(0, '', '', $query_args);
2565
+	}
2566
+
2567
+
2568
+
2569
+	/**
2570
+	 * Handles deleting specific category.
2571
+	 * @param int $cat_id
2572
+	 */
2573
+	protected function _delete_category($cat_id)
2574
+	{
2575
+		$cat_id = absint($cat_id);
2576
+		wp_delete_term($cat_id, 'espresso_event_categories');
2577
+	}
2578
+
2579
+
2580
+
2581
+	/**
2582
+	 * Handles triggering the update or insertion of a new category.
2583
+	 * @param bool $new_category  true means we're triggering the insert of a new category.
2584
+	 */
2585
+	protected function _insert_or_update_category($new_category)
2586
+	{
2587
+		$cat_id = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2588
+		$success = 0; //we already have a success message so lets not send another.
2589
+		if ($cat_id) {
2590
+			$query_args = array(
2591
+				'action'     => 'edit_category',
2592
+				'EVT_CAT_ID' => $cat_id,
2593
+			);
2594
+		} else {
2595
+			$query_args = array('action' => 'add_category');
2596
+		}
2597
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2598
+	}
2599
+
2600
+
2601
+
2602
+	/**
2603
+	 * Inserts or updates category
2604
+	 * @param bool $update (true indicates we're updating a category).
2605
+	 * @return bool|mixed|string
2606
+	 */
2607
+	private function _insert_category($update = false)
2608
+	{
2609
+		$cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2610
+		$category_name = isset($this->_req_data['category_name']) ? $this->_req_data['category_name'] : '';
2611
+		$category_desc = isset($this->_req_data['category_desc']) ? $this->_req_data['category_desc'] : '';
2612
+		$category_parent = isset($this->_req_data['category_parent']) ? $this->_req_data['category_parent'] : 0;
2613
+		if (empty($category_name)) {
2614
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2615
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2616
+			return false;
2617
+		}
2618
+		$term_args = array(
2619
+			'name'        => $category_name,
2620
+			'description' => $category_desc,
2621
+			'parent'      => $category_parent,
2622
+		);
2623
+		//was the category_identifier input disabled?
2624
+		if (isset($this->_req_data['category_identifier'])) {
2625
+			$term_args['slug'] = $this->_req_data['category_identifier'];
2626
+		}
2627
+		$insert_ids = $update
2628
+			? wp_update_term($cat_id, 'espresso_event_categories', $term_args)
2629
+			: wp_insert_term($category_name, 'espresso_event_categories', $term_args);
2630
+		if ( ! is_array($insert_ids)) {
2631
+			$msg = esc_html__(
2632
+				'An error occurred and the category has not been saved to the database.',
2633
+				'event_espresso'
2634
+			);
2635
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2636
+		} else {
2637
+			$cat_id = $insert_ids['term_id'];
2638
+			$msg = sprintf(esc_html__('The category %s was successfully saved', 'event_espresso'), $category_name);
2639
+			EE_Error::add_success($msg);
2640
+		}
2641
+		return $cat_id;
2642
+	}
2643
+
2644
+
2645
+
2646
+	/**
2647
+	 * Gets categories or count of categories matching the arguments in the request.
2648
+	 * @param int  $per_page
2649
+	 * @param int  $current_page
2650
+	 * @param bool $count
2651
+	 * @return EE_Base_Class[]|EE_Term_Taxonomy[]|int
2652
+	 */
2653
+	public function get_categories($per_page = 10, $current_page = 1, $count = false)
2654
+	{
2655
+		//testing term stuff
2656
+		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'Term.term_id';
2657
+		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2658
+		$limit = ($current_page - 1) * $per_page;
2659
+		$where = array('taxonomy' => 'espresso_event_categories');
2660
+		if (isset($this->_req_data['s'])) {
2661
+			$sstr = '%' . $this->_req_data['s'] . '%';
2662
+			$where['OR'] = array(
2663
+				'Term.name'   => array('LIKE', $sstr),
2664
+				'description' => array('LIKE', $sstr),
2665
+			);
2666
+		}
2667
+		$query_params = array(
2668
+			$where,
2669
+			'order_by'   => array($orderby => $order),
2670
+			'limit'      => $limit . ',' . $per_page,
2671
+			'force_join' => array('Term'),
2672
+		);
2673
+		$categories = $count
2674
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2675
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2676
+		return $categories;
2677
+	}
2678
+
2679
+	/* end category stuff */
2680
+	/**************/
2681
+
2682
+
2683
+	/**
2684
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2685
+	 * @throws EE_Error
2686
+	 */
2687
+	public function save_timezonestring_setting()
2688
+	{
2689
+		$timezone_string = isset($this->_req_data['timezone_selected'])
2690
+			? $this->_req_data['timezone_selected']
2691
+			: '';
2692
+		if  (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false))
2693
+		{
2694
+			EE_Error::add_error(
2695
+				esc_html('An invalid timezone string submitted.', 'event_espresso'),
2696
+				__FILE__, __FUNCTION__, __LINE__
2697
+			);
2698
+			$this->_template_args['error'] = true;
2699
+			$this->_return_json();
2700
+		}
2701
+
2702
+		update_option('timezone_string', $timezone_string);
2703
+		EE_Error::add_success(
2704
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2705
+		);
2706
+		$this->_template_args['success'] = true;
2707
+		$this->_return_json(true, array('action' => 'create_new'));
2708
+	}
2709 2709
 }
2710 2710
 //end class Events_Admin_Page
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 2 patches
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -155,8 +155,8 @@  discard block
 block discarded – undo
155 155
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156 156
         } else {
157 157
             //set default formats for date and time
158
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
158
+            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
159
+            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
160 160
         }
161 161
         //if db model is instantiating
162 162
         if ($bydb) {
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
      */
479 479
     public function get_format($full = true)
480 480
     {
481
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
481
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482 482
     }
483 483
 
484 484
 
@@ -587,7 +587,7 @@  discard block
 block discarded – undo
587 587
         $model = $this->get_model();
588 588
         $model->field_settings_for($fieldname);
589 589
         $cache_type = $pretty ? 'pretty' : 'standard';
590
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
590
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
591 591
         if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592 592
             return $this->_cached_properties[$fieldname][$cache_type];
593 593
         }
@@ -802,7 +802,7 @@  discard block
 block discarded – undo
802 802
         $current_cache_id = ''
803 803
     ) {
804 804
         // verify that incoming object is of the correct type
805
-        $obj_class = 'EE_' . $relationName;
805
+        $obj_class = 'EE_'.$relationName;
806 806
         if ($newly_saved_object instanceof $obj_class) {
807 807
             /* @type EE_Base_Class $newly_saved_object */
808 808
             // now get the type of relation
@@ -1288,7 +1288,7 @@  discard block
 block discarded – undo
1288 1288
      */
1289 1289
     public function get_i18n_datetime($field_name, $format = '')
1290 1290
     {
1291
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1291
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1292 1292
         return date_i18n(
1293 1293
             $format,
1294 1294
             EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
@@ -1426,8 +1426,8 @@  discard block
 block discarded – undo
1426 1426
         }
1427 1427
         $original_timezone = $this->_timezone;
1428 1428
         $this->set_timezone($timezone);
1429
-        $fn = (array)$field_name;
1430
-        $args = array_merge($fn, (array)$args);
1429
+        $fn = (array) $field_name;
1430
+        $args = array_merge($fn, (array) $args);
1431 1431
         if ( ! method_exists($this, $callback)) {
1432 1432
             throw new EE_Error(
1433 1433
                 sprintf(
@@ -1439,8 +1439,8 @@  discard block
 block discarded – undo
1439 1439
                 )
1440 1440
             );
1441 1441
         }
1442
-        $args = (array)$args;
1443
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1442
+        $args = (array) $args;
1443
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1444 1444
         $this->set_timezone($original_timezone);
1445 1445
         return $return;
1446 1446
     }
@@ -1579,14 +1579,14 @@  discard block
 block discarded – undo
1579 1579
          * @param array         $set_cols_n_values
1580 1580
          * @param EE_Base_Class $model_object
1581 1581
          */
1582
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1582
+        $set_cols_n_values = (array) apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1583 1583
             $this);
1584 1584
         //set attributes as provided in $set_cols_n_values
1585 1585
         foreach ($set_cols_n_values as $column => $value) {
1586 1586
             $this->set($column, $value);
1587 1587
         }
1588 1588
         // no changes ? then don't do anything
1589
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1589
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1590 1590
             return 0;
1591 1591
         }
1592 1592
         /**
@@ -1638,8 +1638,8 @@  discard block
 block discarded – undo
1638 1638
                                 __('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1639 1639
                                     'event_espresso'),
1640 1640
                                 get_class($this),
1641
-                                get_class($model) . '::instance()->add_to_entity_map()',
1642
-                                get_class($model) . '::instance()->get_one_by_ID()',
1641
+                                get_class($model).'::instance()->add_to_entity_map()',
1642
+                                get_class($model).'::instance()->get_one_by_ID()',
1643 1643
                                 '<br />'
1644 1644
                             )
1645 1645
                         );
@@ -1772,7 +1772,7 @@  discard block
 block discarded – undo
1772 1772
      */
1773 1773
     public function get_model()
1774 1774
     {
1775
-        if( ! $this->_model){
1775
+        if ( ! $this->_model) {
1776 1776
             $modelName = self::_get_model_classname(get_class($this));
1777 1777
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1778 1778
         } else {
@@ -1915,7 +1915,7 @@  discard block
 block discarded – undo
1915 1915
         if (strpos($model_name, "EE_") === 0) {
1916 1916
             $model_classname = str_replace("EE_", "EEM_", $model_name);
1917 1917
         } else {
1918
-            $model_classname = "EEM_" . $model_name;
1918
+            $model_classname = "EEM_".$model_name;
1919 1919
         }
1920 1920
         return $model_classname;
1921 1921
     }
@@ -2302,7 +2302,7 @@  discard block
 block discarded – undo
2302 2302
      */
2303 2303
     protected function _property_exists($properties)
2304 2304
     {
2305
-        foreach ((array)$properties as $property_name) {
2305
+        foreach ((array) $properties as $property_name) {
2306 2306
             //first make sure this property exists
2307 2307
             if ( ! $this->_fields[$property_name]) {
2308 2308
                 throw new EE_Error(
@@ -2632,8 +2632,8 @@  discard block
 block discarded – undo
2632 2632
                         __('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2633 2633
                             'event_espresso'),
2634 2634
                         $this->ID(),
2635
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2636
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2635
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
2636
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
2637 2637
                     )
2638 2638
                 );
2639 2639
             }
@@ -2693,7 +2693,7 @@  discard block
 block discarded – undo
2693 2693
         $model = $this->get_model();
2694 2694
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2695 2695
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
2696
-                $classname = 'EE_' . $model->get_this_model_name();
2696
+                $classname = 'EE_'.$model->get_this_model_name();
2697 2697
                 if (
2698 2698
                     $this->get_one_from_cache($relation_name) instanceof $classname
2699 2699
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.
Indentation   +2709 added lines, -2709 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 do_action('AHEE_log', __FILE__, ' FILE LOADED', '');
5 5
 
@@ -25,2714 +25,2714 @@  discard block
 block discarded – undo
25 25
 abstract class EE_Base_Class
26 26
 {
27 27
 
28
-    /**
29
-     * This is an array of the original properties and values provided during construction
30
-     * of this model object. (keys are model field names, values are their values).
31
-     * This list is important to remember so that when we are merging data from the db, we know
32
-     * which values to override and which to not override.
33
-     *
34
-     * @var array
35
-     */
36
-    protected $_props_n_values_provided_in_constructor;
37
-
38
-    /**
39
-     * Timezone
40
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
41
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
42
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
43
-     * access to it.
44
-     *
45
-     * @var string
46
-     */
47
-    protected $_timezone;
48
-
49
-
50
-
51
-    /**
52
-     * date format
53
-     * pattern or format for displaying dates
54
-     *
55
-     * @var string $_dt_frmt
56
-     */
57
-    protected $_dt_frmt;
58
-
59
-
60
-
61
-    /**
62
-     * time format
63
-     * pattern or format for displaying time
64
-     *
65
-     * @var string $_tm_frmt
66
-     */
67
-    protected $_tm_frmt;
68
-
69
-
70
-
71
-    /**
72
-     * This property is for holding a cached array of object properties indexed by property name as the key.
73
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
74
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
75
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
76
-     *
77
-     * @var array
78
-     */
79
-    protected $_cached_properties = array();
80
-
81
-    /**
82
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
83
-     * single
84
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
85
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
86
-     * all others have an array)
87
-     *
88
-     * @var array
89
-     */
90
-    protected $_model_relations = array();
91
-
92
-    /**
93
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
94
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
95
-     *
96
-     * @var array
97
-     */
98
-    protected $_fields = array();
99
-
100
-    /**
101
-     * @var boolean indicating whether or not this model object is intended to ever be saved
102
-     * For example, we might create model objects intended to only be used for the duration
103
-     * of this request and to be thrown away, and if they were accidentally saved
104
-     * it would be a bug.
105
-     */
106
-    protected $_allow_persist = true;
107
-
108
-    /**
109
-     * @var boolean indicating whether or not this model object's properties have changed since construction
110
-     */
111
-    protected $_has_changes = false;
112
-
113
-    /**
114
-     * @var EEM_Base
115
-     */
116
-    protected $_model;
117
-
118
-
119
-
120
-    /**
121
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
122
-     * play nice
123
-     *
124
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
125
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
126
-     *                                                         TXN_amount, QST_name, etc) and values are their values
127
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
128
-     *                                                         corresponding db model or not.
129
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
130
-     *                                                         be in when instantiating a EE_Base_Class object.
131
-     * @param array   $date_formats                            An array of date formats to set on construct where first
132
-     *                                                         value is the date_format and second value is the time
133
-     *                                                         format.
134
-     * @throws EE_Error
135
-     */
136
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
137
-    {
138
-        $className = get_class($this);
139
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
140
-        $model = $this->get_model();
141
-        $model_fields = $model->field_settings(false);
142
-        // ensure $fieldValues is an array
143
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
144
-        // EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
145
-        // verify client code has not passed any invalid field names
146
-        foreach ($fieldValues as $field_name => $field_value) {
147
-            if ( ! isset($model_fields[$field_name])) {
148
-                throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
149
-                    "event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
150
-            }
151
-        }
152
-        // EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
153
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
154
-        if ( ! empty($date_formats) && is_array($date_formats)) {
155
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156
-        } else {
157
-            //set default formats for date and time
158
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
160
-        }
161
-        //if db model is instantiating
162
-        if ($bydb) {
163
-            //client code has indicated these field values are from the database
164
-            foreach ($model_fields as $fieldName => $field) {
165
-                $this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
166
-            }
167
-        } else {
168
-            //we're constructing a brand
169
-            //new instance of the model object. Generally, this means we'll need to do more field validation
170
-            foreach ($model_fields as $fieldName => $field) {
171
-                $this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
172
-            }
173
-        }
174
-        //remember what values were passed to this constructor
175
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
176
-        //remember in entity mapper
177
-        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
178
-            $model->add_to_entity_map($this);
179
-        }
180
-        //setup all the relations
181
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
182
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
183
-                $this->_model_relations[$relation_name] = null;
184
-            } else {
185
-                $this->_model_relations[$relation_name] = array();
186
-            }
187
-        }
188
-        /**
189
-         * Action done at the end of each model object construction
190
-         *
191
-         * @param EE_Base_Class $this the model object just created
192
-         */
193
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
194
-    }
195
-
196
-
197
-
198
-    /**
199
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
200
-     *
201
-     * @return boolean
202
-     */
203
-    public function allow_persist()
204
-    {
205
-        return $this->_allow_persist;
206
-    }
207
-
208
-
209
-
210
-    /**
211
-     * Sets whether or not this model object should be allowed to be saved to the DB.
212
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
213
-     * you got new information that somehow made you change your mind.
214
-     *
215
-     * @param boolean $allow_persist
216
-     * @return boolean
217
-     */
218
-    public function set_allow_persist($allow_persist)
219
-    {
220
-        return $this->_allow_persist = $allow_persist;
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * Gets the field's original value when this object was constructed during this request.
227
-     * This can be helpful when determining if a model object has changed or not
228
-     *
229
-     * @param string $field_name
230
-     * @return mixed|null
231
-     * @throws \EE_Error
232
-     */
233
-    public function get_original($field_name)
234
-    {
235
-        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
236
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
237
-        ) {
238
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
239
-        } else {
240
-            return null;
241
-        }
242
-    }
243
-
244
-
245
-
246
-    /**
247
-     * @param EE_Base_Class $obj
248
-     * @return string
249
-     */
250
-    public function get_class($obj)
251
-    {
252
-        return get_class($obj);
253
-    }
254
-
255
-
256
-
257
-    /**
258
-     * Overrides parent because parent expects old models.
259
-     * This also doesn't do any validation, and won't work for serialized arrays
260
-     *
261
-     * @param    string $field_name
262
-     * @param    mixed  $field_value
263
-     * @param bool      $use_default
264
-     * @throws \EE_Error
265
-     */
266
-    public function set($field_name, $field_value, $use_default = false)
267
-    {
268
-        // if not using default and nothing has changed, and object has already been setup (has ID),
269
-        // then don't do anything
270
-        if (
271
-            ! $use_default
272
-            && $this->_fields[$field_name] === $field_value
273
-            && $this->ID()
274
-        ) {
275
-            return;
276
-        }
277
-        $model = $this->get_model();
278
-        $this->_has_changes = true;
279
-        $field_obj = $model->field_settings_for($field_name);
280
-        if ($field_obj instanceof EE_Model_Field_Base) {
281
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
282
-            if ($field_obj instanceof EE_Datetime_Field) {
283
-                $field_obj->set_timezone($this->_timezone);
284
-                $field_obj->set_date_format($this->_dt_frmt);
285
-                $field_obj->set_time_format($this->_tm_frmt);
286
-            }
287
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
288
-            //should the value be null?
289
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
290
-                $this->_fields[$field_name] = $field_obj->get_default_value();
291
-                /**
292
-                 * To save having to refactor all the models, if a default value is used for a
293
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
294
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
295
-                 * object.
296
-                 *
297
-                 * @since 4.6.10+
298
-                 */
299
-                if (
300
-                    $field_obj instanceof EE_Datetime_Field
301
-                    && $this->_fields[$field_name] !== null
302
-                    && ! $this->_fields[$field_name] instanceof DateTime
303
-                ) {
304
-                    empty($this->_fields[$field_name])
305
-                        ? $this->set($field_name, time())
306
-                        : $this->set($field_name, $this->_fields[$field_name]);
307
-                }
308
-            } else {
309
-                $this->_fields[$field_name] = $holder_of_value;
310
-            }
311
-            //if we're not in the constructor...
312
-            //now check if what we set was a primary key
313
-            if (
314
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
315
-                $this->_props_n_values_provided_in_constructor
316
-                && $field_value
317
-                && $field_name === $model->primary_key_name()
318
-            ) {
319
-                //if so, we want all this object's fields to be filled either with
320
-                //what we've explicitly set on this model
321
-                //or what we have in the db
322
-                // echo "setting primary key!";
323
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
324
-                $obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
325
-                foreach ($fields_on_model as $field_obj) {
326
-                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
327
-                         && $field_obj->get_name() !== $field_name
328
-                    ) {
329
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
330
-                    }
331
-                }
332
-                //oh this model object has an ID? well make sure its in the entity mapper
333
-                $model->add_to_entity_map($this);
334
-            }
335
-            //let's unset any cache for this field_name from the $_cached_properties property.
336
-            $this->_clear_cached_property($field_name);
337
-        } else {
338
-            throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
339
-                "event_espresso"), $field_name));
340
-        }
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * This sets the field value on the db column if it exists for the given $column_name or
347
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
348
-     *
349
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
350
-     * @param string $field_name  Must be the exact column name.
351
-     * @param mixed  $field_value The value to set.
352
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
353
-     * @throws \EE_Error
354
-     */
355
-    public function set_field_or_extra_meta($field_name, $field_value)
356
-    {
357
-        if ($this->get_model()->has_field($field_name)) {
358
-            $this->set($field_name, $field_value);
359
-            return true;
360
-        } else {
361
-            //ensure this object is saved first so that extra meta can be properly related.
362
-            $this->save();
363
-            return $this->update_extra_meta($field_name, $field_value);
364
-        }
365
-    }
366
-
367
-
368
-
369
-    /**
370
-     * This retrieves the value of the db column set on this class or if that's not present
371
-     * it will attempt to retrieve from extra_meta if found.
372
-     * Example Usage:
373
-     * Via EE_Message child class:
374
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
375
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
376
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
377
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
378
-     * value for those extra fields dynamically via the EE_message object.
379
-     *
380
-     * @param  string $field_name expecting the fully qualified field name.
381
-     * @return mixed|null  value for the field if found.  null if not found.
382
-     * @throws \EE_Error
383
-     */
384
-    public function get_field_or_extra_meta($field_name)
385
-    {
386
-        if ($this->get_model()->has_field($field_name)) {
387
-            $column_value = $this->get($field_name);
388
-        } else {
389
-            //This isn't a column in the main table, let's see if it is in the extra meta.
390
-            $column_value = $this->get_extra_meta($field_name, true, null);
391
-        }
392
-        return $column_value;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
399
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
400
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
401
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
402
-     *
403
-     * @access public
404
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
405
-     * @return void
406
-     * @throws \EE_Error
407
-     */
408
-    public function set_timezone($timezone = '')
409
-    {
410
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
411
-        //make sure we clear all cached properties because they won't be relevant now
412
-        $this->_clear_cached_properties();
413
-        //make sure we update field settings and the date for all EE_Datetime_Fields
414
-        $model_fields = $this->get_model()->field_settings(false);
415
-        foreach ($model_fields as $field_name => $field_obj) {
416
-            if ($field_obj instanceof EE_Datetime_Field) {
417
-                $field_obj->set_timezone($this->_timezone);
418
-                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
419
-                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
420
-                }
421
-            }
422
-        }
423
-    }
424
-
425
-
426
-
427
-    /**
428
-     * This just returns whatever is set for the current timezone.
429
-     *
430
-     * @access public
431
-     * @return string timezone string
432
-     */
433
-    public function get_timezone()
434
-    {
435
-        return $this->_timezone;
436
-    }
437
-
438
-
439
-
440
-    /**
441
-     * This sets the internal date format to what is sent in to be used as the new default for the class
442
-     * internally instead of wp set date format options
443
-     *
444
-     * @since 4.6
445
-     * @param string $format should be a format recognizable by PHP date() functions.
446
-     */
447
-    public function set_date_format($format)
448
-    {
449
-        $this->_dt_frmt = $format;
450
-        //clear cached_properties because they won't be relevant now.
451
-        $this->_clear_cached_properties();
452
-    }
453
-
454
-
455
-
456
-    /**
457
-     * This sets the internal time format string to what is sent in to be used as the new default for the
458
-     * class internally instead of wp set time format options.
459
-     *
460
-     * @since 4.6
461
-     * @param string $format should be a format recognizable by PHP date() functions.
462
-     */
463
-    public function set_time_format($format)
464
-    {
465
-        $this->_tm_frmt = $format;
466
-        //clear cached_properties because they won't be relevant now.
467
-        $this->_clear_cached_properties();
468
-    }
469
-
470
-
471
-
472
-    /**
473
-     * This returns the current internal set format for the date and time formats.
474
-     *
475
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
476
-     *                             where the first value is the date format and the second value is the time format.
477
-     * @return mixed string|array
478
-     */
479
-    public function get_format($full = true)
480
-    {
481
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482
-    }
483
-
484
-
485
-
486
-    /**
487
-     * cache
488
-     * stores the passed model object on the current model object.
489
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
490
-     *
491
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
492
-     *                                       'Registration' associated with this model object
493
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
494
-     *                                       that could be a payment or a registration)
495
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
496
-     *                                       items which will be stored in an array on this object
497
-     * @throws EE_Error
498
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
499
-     *                  related thing, no array)
500
-     */
501
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
502
-    {
503
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
504
-        if ( ! $object_to_cache instanceof EE_Base_Class) {
505
-            return false;
506
-        }
507
-        // also get "how" the object is related, or throw an error
508
-        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
509
-            throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
510
-                $relationName, get_class($this)));
511
-        }
512
-        // how many things are related ?
513
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
514
-            // if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
515
-            // so for these model objects just set it to be cached
516
-            $this->_model_relations[$relationName] = $object_to_cache;
517
-            $return = true;
518
-        } else {
519
-            // otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
520
-            // eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
521
-            if ( ! is_array($this->_model_relations[$relationName])) {
522
-                // if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
523
-                $this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
524
-                    ? array($this->_model_relations[$relationName]) : array();
525
-            }
526
-            // first check for a cache_id which is normally empty
527
-            if ( ! empty($cache_id)) {
528
-                // if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
529
-                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
530
-                $return = $cache_id;
531
-            } elseif ($object_to_cache->ID()) {
532
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
533
-                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
534
-                $return = $object_to_cache->ID();
535
-            } else {
536
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
537
-                $this->_model_relations[$relationName][] = $object_to_cache;
538
-                // move the internal pointer to the end of the array
539
-                end($this->_model_relations[$relationName]);
540
-                // and grab the key so that we can return it
541
-                $return = key($this->_model_relations[$relationName]);
542
-            }
543
-        }
544
-        return $return;
545
-    }
546
-
547
-
548
-
549
-    /**
550
-     * For adding an item to the cached_properties property.
551
-     *
552
-     * @access protected
553
-     * @param string      $fieldname the property item the corresponding value is for.
554
-     * @param mixed       $value     The value we are caching.
555
-     * @param string|null $cache_type
556
-     * @return void
557
-     * @throws \EE_Error
558
-     */
559
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
560
-    {
561
-        //first make sure this property exists
562
-        $this->get_model()->field_settings_for($fieldname);
563
-        $cache_type = empty($cache_type) ? 'standard' : $cache_type;
564
-        $this->_cached_properties[$fieldname][$cache_type] = $value;
565
-    }
566
-
567
-
568
-
569
-    /**
570
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
571
-     * This also SETS the cache if we return the actual property!
572
-     *
573
-     * @param string $fieldname        the name of the property we're trying to retrieve
574
-     * @param bool   $pretty
575
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
576
-     *                                 (in cases where the same property may be used for different outputs
577
-     *                                 - i.e. datetime, money etc.)
578
-     *                                 It can also accept certain pre-defined "schema" strings
579
-     *                                 to define how to output the property.
580
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
581
-     * @return mixed                   whatever the value for the property is we're retrieving
582
-     * @throws \EE_Error
583
-     */
584
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
585
-    {
586
-        //verify the field exists
587
-        $model = $this->get_model();
588
-        $model->field_settings_for($fieldname);
589
-        $cache_type = $pretty ? 'pretty' : 'standard';
590
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
591
-        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592
-            return $this->_cached_properties[$fieldname][$cache_type];
593
-        }
594
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
595
-        $this->_set_cached_property($fieldname, $value, $cache_type);
596
-        return $value;
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     * If the cache didn't fetch the needed item, this fetches it.
603
-     * @param string $fieldname
604
-     * @param bool $pretty
605
-     * @param string $extra_cache_ref
606
-     * @return mixed
607
-     */
608
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
609
-    {
610
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
611
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
612
-        if ($field_obj instanceof EE_Datetime_Field) {
613
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
614
-        }
615
-        if ( ! isset($this->_fields[$fieldname])) {
616
-            $this->_fields[$fieldname] = null;
617
-        }
618
-        $value = $pretty
619
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
620
-            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
621
-        return $value;
622
-    }
623
-
624
-
625
-
626
-    /**
627
-     * set timezone, formats, and output for EE_Datetime_Field objects
628
-     *
629
-     * @param \EE_Datetime_Field $datetime_field
630
-     * @param bool               $pretty
631
-     * @param null $date_or_time
632
-     * @return void
633
-     * @throws \EE_Error
634
-     */
635
-    protected function _prepare_datetime_field(
636
-        EE_Datetime_Field $datetime_field,
637
-        $pretty = false,
638
-        $date_or_time = null
639
-    ) {
640
-        $datetime_field->set_timezone($this->_timezone);
641
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
642
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
643
-        //set the output returned
644
-        switch ($date_or_time) {
645
-            case 'D' :
646
-                $datetime_field->set_date_time_output('date');
647
-                break;
648
-            case 'T' :
649
-                $datetime_field->set_date_time_output('time');
650
-                break;
651
-            default :
652
-                $datetime_field->set_date_time_output();
653
-        }
654
-    }
655
-
656
-
657
-
658
-    /**
659
-     * This just takes care of clearing out the cached_properties
660
-     *
661
-     * @return void
662
-     */
663
-    protected function _clear_cached_properties()
664
-    {
665
-        $this->_cached_properties = array();
666
-    }
667
-
668
-
669
-
670
-    /**
671
-     * This just clears out ONE property if it exists in the cache
672
-     *
673
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
674
-     * @return void
675
-     */
676
-    protected function _clear_cached_property($property_name)
677
-    {
678
-        if (isset($this->_cached_properties[$property_name])) {
679
-            unset($this->_cached_properties[$property_name]);
680
-        }
681
-    }
682
-
683
-
684
-
685
-    /**
686
-     * Ensures that this related thing is a model object.
687
-     *
688
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
689
-     * @param string $model_name   name of the related thing, eg 'Attendee',
690
-     * @return EE_Base_Class
691
-     * @throws \EE_Error
692
-     */
693
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
694
-    {
695
-        $other_model_instance = self::_get_model_instance_with_name(
696
-            self::_get_model_classname($model_name),
697
-            $this->_timezone
698
-        );
699
-        return $other_model_instance->ensure_is_obj($object_or_id);
700
-    }
701
-
702
-
703
-
704
-    /**
705
-     * Forgets the cached model of the given relation Name. So the next time we request it,
706
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
707
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
708
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
709
-     *
710
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
711
-     *                                                     Eg 'Registration'
712
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
713
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
714
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
715
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
716
-     *                                                     this is HasMany or HABTM.
717
-     * @throws EE_Error
718
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
719
-     *                       relation from all
720
-     */
721
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
722
-    {
723
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
724
-        $index_in_cache = '';
725
-        if ( ! $relationship_to_model) {
726
-            throw new EE_Error(
727
-                sprintf(
728
-                    __("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
729
-                    $relationName,
730
-                    get_class($this)
731
-                )
732
-            );
733
-        }
734
-        if ($clear_all) {
735
-            $obj_removed = true;
736
-            $this->_model_relations[$relationName] = null;
737
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
738
-            $obj_removed = $this->_model_relations[$relationName];
739
-            $this->_model_relations[$relationName] = null;
740
-        } else {
741
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
742
-                && $object_to_remove_or_index_into_array->ID()
743
-            ) {
744
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
745
-                if (is_array($this->_model_relations[$relationName])
746
-                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
747
-                ) {
748
-                    $index_found_at = null;
749
-                    //find this object in the array even though it has a different key
750
-                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
751
-                        if (
752
-                            $obj instanceof EE_Base_Class
753
-                            && (
754
-                                $obj == $object_to_remove_or_index_into_array
755
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
756
-                            )
757
-                        ) {
758
-                            $index_found_at = $index;
759
-                            break;
760
-                        }
761
-                    }
762
-                    if ($index_found_at) {
763
-                        $index_in_cache = $index_found_at;
764
-                    } else {
765
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
766
-                        //if it wasn't in it to begin with. So we're done
767
-                        return $object_to_remove_or_index_into_array;
768
-                    }
769
-                }
770
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
771
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
772
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
773
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
774
-                        $index_in_cache = $index;
775
-                    }
776
-                }
777
-            } else {
778
-                $index_in_cache = $object_to_remove_or_index_into_array;
779
-            }
780
-            //supposedly we've found it. But it could just be that the client code
781
-            //provided a bad index/object
782
-            if (
783
-            isset(
784
-                $this->_model_relations[$relationName],
785
-                $this->_model_relations[$relationName][$index_in_cache]
786
-            )
787
-            ) {
788
-                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
789
-                unset($this->_model_relations[$relationName][$index_in_cache]);
790
-            } else {
791
-                //that thing was never cached anyways.
792
-                $obj_removed = null;
793
-            }
794
-        }
795
-        return $obj_removed;
796
-    }
797
-
798
-
799
-
800
-    /**
801
-     * update_cache_after_object_save
802
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
803
-     * obtained after being saved to the db
804
-     *
805
-     * @param string         $relationName       - the type of object that is cached
806
-     * @param \EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
807
-     * @param string         $current_cache_id   - the ID that was used when originally caching the object
808
-     * @return boolean TRUE on success, FALSE on fail
809
-     * @throws \EE_Error
810
-     */
811
-    public function update_cache_after_object_save(
812
-        $relationName,
813
-        EE_Base_Class $newly_saved_object,
814
-        $current_cache_id = ''
815
-    ) {
816
-        // verify that incoming object is of the correct type
817
-        $obj_class = 'EE_' . $relationName;
818
-        if ($newly_saved_object instanceof $obj_class) {
819
-            /* @type EE_Base_Class $newly_saved_object */
820
-            // now get the type of relation
821
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
822
-            // if this is a 1:1 relationship
823
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
824
-                // then just replace the cached object with the newly saved object
825
-                $this->_model_relations[$relationName] = $newly_saved_object;
826
-                return true;
827
-                // or if it's some kind of sordid feral polyamorous relationship...
828
-            } elseif (is_array($this->_model_relations[$relationName])
829
-                      && isset($this->_model_relations[$relationName][$current_cache_id])
830
-            ) {
831
-                // then remove the current cached item
832
-                unset($this->_model_relations[$relationName][$current_cache_id]);
833
-                // and cache the newly saved object using it's new ID
834
-                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
835
-                return true;
836
-            }
837
-        }
838
-        return false;
839
-    }
840
-
841
-
842
-
843
-    /**
844
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
845
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
846
-     *
847
-     * @param string $relationName
848
-     * @return EE_Base_Class
849
-     */
850
-    public function get_one_from_cache($relationName)
851
-    {
852
-        $cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
853
-            : null;
854
-        if (is_array($cached_array_or_object)) {
855
-            return array_shift($cached_array_or_object);
856
-        } else {
857
-            return $cached_array_or_object;
858
-        }
859
-    }
860
-
861
-
862
-
863
-    /**
864
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
865
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
866
-     *
867
-     * @param string $relationName
868
-     * @throws \EE_Error
869
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
870
-     */
871
-    public function get_all_from_cache($relationName)
872
-    {
873
-        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
874
-        // if the result is not an array, but exists, make it an array
875
-        $objects = is_array($objects) ? $objects : array($objects);
876
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
877
-        //basically, if this model object was stored in the session, and these cached model objects
878
-        //already have IDs, let's make sure they're in their model's entity mapper
879
-        //otherwise we will have duplicates next time we call
880
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
881
-        $model = EE_Registry::instance()->load_model($relationName);
882
-        foreach ($objects as $model_object) {
883
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
884
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
885
-                if ($model_object->ID()) {
886
-                    $model->add_to_entity_map($model_object);
887
-                }
888
-            } else {
889
-                throw new EE_Error(
890
-                    sprintf(
891
-                        __(
892
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
893
-                            'event_espresso'
894
-                        ),
895
-                        $relationName,
896
-                        gettype($model_object)
897
-                    )
898
-                );
899
-            }
900
-        }
901
-        return $objects;
902
-    }
903
-
904
-
905
-
906
-    /**
907
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
908
-     * matching the given query conditions.
909
-     *
910
-     * @param null  $field_to_order_by  What field is being used as the reference point.
911
-     * @param int   $limit              How many objects to return.
912
-     * @param array $query_params       Any additional conditions on the query.
913
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
914
-     *                                  you can indicate just the columns you want returned
915
-     * @return array|EE_Base_Class[]
916
-     * @throws \EE_Error
917
-     */
918
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
919
-    {
920
-        $model = $this->get_model();
921
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
922
-            ? $model->get_primary_key_field()->get_name()
923
-            : $field_to_order_by;
924
-        $current_value = ! empty($field) ? $this->get($field) : null;
925
-        if (empty($field) || empty($current_value)) {
926
-            return array();
927
-        }
928
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
929
-    }
930
-
931
-
932
-
933
-    /**
934
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
935
-     * matching the given query conditions.
936
-     *
937
-     * @param null  $field_to_order_by  What field is being used as the reference point.
938
-     * @param int   $limit              How many objects to return.
939
-     * @param array $query_params       Any additional conditions on the query.
940
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
941
-     *                                  you can indicate just the columns you want returned
942
-     * @return array|EE_Base_Class[]
943
-     * @throws \EE_Error
944
-     */
945
-    public function previous_x(
946
-        $field_to_order_by = null,
947
-        $limit = 1,
948
-        $query_params = array(),
949
-        $columns_to_select = null
950
-    ) {
951
-        $model = $this->get_model();
952
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
953
-            ? $model->get_primary_key_field()->get_name()
954
-            : $field_to_order_by;
955
-        $current_value = ! empty($field) ? $this->get($field) : null;
956
-        if (empty($field) || empty($current_value)) {
957
-            return array();
958
-        }
959
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
960
-    }
961
-
962
-
963
-
964
-    /**
965
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
966
-     * matching the given query conditions.
967
-     *
968
-     * @param null  $field_to_order_by  What field is being used as the reference point.
969
-     * @param array $query_params       Any additional conditions on the query.
970
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
971
-     *                                  you can indicate just the columns you want returned
972
-     * @return array|EE_Base_Class
973
-     * @throws \EE_Error
974
-     */
975
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
976
-    {
977
-        $model = $this->get_model();
978
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
979
-            ? $model->get_primary_key_field()->get_name()
980
-            : $field_to_order_by;
981
-        $current_value = ! empty($field) ? $this->get($field) : null;
982
-        if (empty($field) || empty($current_value)) {
983
-            return array();
984
-        }
985
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
986
-    }
987
-
988
-
989
-
990
-    /**
991
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
992
-     * matching the given query conditions.
993
-     *
994
-     * @param null  $field_to_order_by  What field is being used as the reference point.
995
-     * @param array $query_params       Any additional conditions on the query.
996
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
997
-     *                                  you can indicate just the column you want returned
998
-     * @return array|EE_Base_Class
999
-     * @throws \EE_Error
1000
-     */
1001
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1002
-    {
1003
-        $model = $this->get_model();
1004
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1005
-            ? $model->get_primary_key_field()->get_name()
1006
-            : $field_to_order_by;
1007
-        $current_value = ! empty($field) ? $this->get($field) : null;
1008
-        if (empty($field) || empty($current_value)) {
1009
-            return array();
1010
-        }
1011
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1012
-    }
1013
-
1014
-
1015
-
1016
-    /**
1017
-     * Overrides parent because parent expects old models.
1018
-     * This also doesn't do any validation, and won't work for serialized arrays
1019
-     *
1020
-     * @param string $field_name
1021
-     * @param mixed  $field_value_from_db
1022
-     * @throws \EE_Error
1023
-     */
1024
-    public function set_from_db($field_name, $field_value_from_db)
1025
-    {
1026
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1027
-        if ($field_obj instanceof EE_Model_Field_Base) {
1028
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1029
-            //eg, a CPT model object could have an entry in the posts table, but no
1030
-            //entry in the meta table. Meaning that all its columns in the meta table
1031
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1032
-            if ($field_value_from_db === null) {
1033
-                if ($field_obj->is_nullable()) {
1034
-                    //if the field allows nulls, then let it be null
1035
-                    $field_value = null;
1036
-                } else {
1037
-                    $field_value = $field_obj->get_default_value();
1038
-                }
1039
-            } else {
1040
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1041
-            }
1042
-            $this->_fields[$field_name] = $field_value;
1043
-            $this->_clear_cached_property($field_name);
1044
-        }
1045
-    }
1046
-
1047
-
1048
-
1049
-    /**
1050
-     * verifies that the specified field is of the correct type
1051
-     *
1052
-     * @param string $field_name
1053
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1054
-     *                                (in cases where the same property may be used for different outputs
1055
-     *                                - i.e. datetime, money etc.)
1056
-     * @return mixed
1057
-     * @throws \EE_Error
1058
-     */
1059
-    public function get($field_name, $extra_cache_ref = null)
1060
-    {
1061
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1062
-    }
1063
-
1064
-
1065
-
1066
-    /**
1067
-     * This method simply returns the RAW unprocessed value for the given property in this class
1068
-     *
1069
-     * @param  string $field_name A valid fieldname
1070
-     * @return mixed              Whatever the raw value stored on the property is.
1071
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1072
-     */
1073
-    public function get_raw($field_name)
1074
-    {
1075
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1076
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1077
-            ? $this->_fields[$field_name]->format('U')
1078
-            : $this->_fields[$field_name];
1079
-    }
1080
-
1081
-
1082
-
1083
-    /**
1084
-     * This is used to return the internal DateTime object used for a field that is a
1085
-     * EE_Datetime_Field.
1086
-     *
1087
-     * @param string $field_name               The field name retrieving the DateTime object.
1088
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1089
-     * @throws \EE_Error
1090
-     *                                         an error is set and false returned.  If the field IS an
1091
-     *                                         EE_Datetime_Field and but the field value is null, then
1092
-     *                                         just null is returned (because that indicates that likely
1093
-     *                                         this field is nullable).
1094
-     */
1095
-    public function get_DateTime_object($field_name)
1096
-    {
1097
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1098
-        if ( ! $field_settings instanceof EE_Datetime_Field) {
1099
-            EE_Error::add_error(
1100
-                sprintf(
1101
-                    __(
1102
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1103
-                        'event_espresso'
1104
-                    ),
1105
-                    $field_name
1106
-                ),
1107
-                __FILE__,
1108
-                __FUNCTION__,
1109
-                __LINE__
1110
-            );
1111
-            return false;
1112
-        }
1113
-        return $this->_fields[$field_name];
1114
-    }
1115
-
1116
-
1117
-
1118
-    /**
1119
-     * To be used in template to immediately echo out the value, and format it for output.
1120
-     * Eg, should call stripslashes and whatnot before echoing
1121
-     *
1122
-     * @param string $field_name      the name of the field as it appears in the DB
1123
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1124
-     *                                (in cases where the same property may be used for different outputs
1125
-     *                                - i.e. datetime, money etc.)
1126
-     * @return void
1127
-     * @throws \EE_Error
1128
-     */
1129
-    public function e($field_name, $extra_cache_ref = null)
1130
-    {
1131
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1132
-    }
1133
-
1134
-
1135
-
1136
-    /**
1137
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1138
-     * can be easily used as the value of form input.
1139
-     *
1140
-     * @param string $field_name
1141
-     * @return void
1142
-     * @throws \EE_Error
1143
-     */
1144
-    public function f($field_name)
1145
-    {
1146
-        $this->e($field_name, 'form_input');
1147
-    }
1148
-
1149
-
1150
-
1151
-    /**
1152
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1153
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1154
-     * to see what options are available.
1155
-     * @param string $field_name
1156
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1157
-     *                                (in cases where the same property may be used for different outputs
1158
-     *                                - i.e. datetime, money etc.)
1159
-     * @return mixed
1160
-     * @throws \EE_Error
1161
-     */
1162
-    public function get_pretty($field_name, $extra_cache_ref = null)
1163
-    {
1164
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1165
-    }
1166
-
1167
-
1168
-
1169
-    /**
1170
-     * This simply returns the datetime for the given field name
1171
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1172
-     * (and the equivalent e_date, e_time, e_datetime).
1173
-     *
1174
-     * @access   protected
1175
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1176
-     * @param string   $dt_frmt      valid datetime format used for date
1177
-     *                               (if '' then we just use the default on the field,
1178
-     *                               if NULL we use the last-used format)
1179
-     * @param string   $tm_frmt      Same as above except this is for time format
1180
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1181
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1182
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1183
-     *                               if field is not a valid dtt field, or void if echoing
1184
-     * @throws \EE_Error
1185
-     */
1186
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1187
-    {
1188
-        // clear cached property
1189
-        $this->_clear_cached_property($field_name);
1190
-        //reset format properties because they are used in get()
1191
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1192
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1193
-        if ($echo) {
1194
-            $this->e($field_name, $date_or_time);
1195
-            return '';
1196
-        }
1197
-        return $this->get($field_name, $date_or_time);
1198
-    }
1199
-
1200
-
1201
-
1202
-    /**
1203
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1204
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1205
-     * other echoes the pretty value for dtt)
1206
-     *
1207
-     * @param  string $field_name name of model object datetime field holding the value
1208
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1209
-     * @return string            datetime value formatted
1210
-     * @throws \EE_Error
1211
-     */
1212
-    public function get_date($field_name, $format = '')
1213
-    {
1214
-        return $this->_get_datetime($field_name, $format, null, 'D');
1215
-    }
1216
-
1217
-
1218
-
1219
-    /**
1220
-     * @param      $field_name
1221
-     * @param string $format
1222
-     * @throws \EE_Error
1223
-     */
1224
-    public function e_date($field_name, $format = '')
1225
-    {
1226
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1227
-    }
1228
-
1229
-
1230
-
1231
-    /**
1232
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1233
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1234
-     * other echoes the pretty value for dtt)
1235
-     *
1236
-     * @param  string $field_name name of model object datetime field holding the value
1237
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1238
-     * @return string             datetime value formatted
1239
-     * @throws \EE_Error
1240
-     */
1241
-    public function get_time($field_name, $format = '')
1242
-    {
1243
-        return $this->_get_datetime($field_name, null, $format, 'T');
1244
-    }
1245
-
1246
-
1247
-
1248
-    /**
1249
-     * @param      $field_name
1250
-     * @param string $format
1251
-     * @throws \EE_Error
1252
-     */
1253
-    public function e_time($field_name, $format = '')
1254
-    {
1255
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1256
-    }
1257
-
1258
-
1259
-
1260
-    /**
1261
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1262
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1263
-     * other echoes the pretty value for dtt)
1264
-     *
1265
-     * @param  string $field_name name of model object datetime field holding the value
1266
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1267
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1268
-     * @return string             datetime value formatted
1269
-     * @throws \EE_Error
1270
-     */
1271
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1272
-    {
1273
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1274
-    }
1275
-
1276
-
1277
-
1278
-    /**
1279
-     * @param string $field_name
1280
-     * @param string $dt_frmt
1281
-     * @param string $tm_frmt
1282
-     * @throws \EE_Error
1283
-     */
1284
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1285
-    {
1286
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1287
-    }
1288
-
1289
-
1290
-
1291
-    /**
1292
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1293
-     *
1294
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1295
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1296
-     *                           on the object will be used.
1297
-     * @return string Date and time string in set locale or false if no field exists for the given
1298
-     * @throws \EE_Error
1299
-     *                           field name.
1300
-     */
1301
-    public function get_i18n_datetime($field_name, $format = '')
1302
-    {
1303
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1304
-        return date_i18n(
1305
-            $format,
1306
-            EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1307
-        );
1308
-    }
1309
-
1310
-
1311
-
1312
-    /**
1313
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1314
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1315
-     * thrown.
1316
-     *
1317
-     * @param  string $field_name The field name being checked
1318
-     * @throws EE_Error
1319
-     * @return EE_Datetime_Field
1320
-     */
1321
-    protected function _get_dtt_field_settings($field_name)
1322
-    {
1323
-        $field = $this->get_model()->field_settings_for($field_name);
1324
-        //check if field is dtt
1325
-        if ($field instanceof EE_Datetime_Field) {
1326
-            return $field;
1327
-        } else {
1328
-            throw new EE_Error(sprintf(__('The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1329
-                'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1330
-        }
1331
-    }
1332
-
1333
-
1334
-
1335
-
1336
-    /**
1337
-     * NOTE ABOUT BELOW:
1338
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1339
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1340
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1341
-     * method and make sure you send the entire datetime value for setting.
1342
-     */
1343
-    /**
1344
-     * sets the time on a datetime property
1345
-     *
1346
-     * @access protected
1347
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1348
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1349
-     * @throws \EE_Error
1350
-     */
1351
-    protected function _set_time_for($time, $fieldname)
1352
-    {
1353
-        $this->_set_date_time('T', $time, $fieldname);
1354
-    }
1355
-
1356
-
1357
-
1358
-    /**
1359
-     * sets the date on a datetime property
1360
-     *
1361
-     * @access protected
1362
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1363
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1364
-     * @throws \EE_Error
1365
-     */
1366
-    protected function _set_date_for($date, $fieldname)
1367
-    {
1368
-        $this->_set_date_time('D', $date, $fieldname);
1369
-    }
1370
-
1371
-
1372
-
1373
-    /**
1374
-     * This takes care of setting a date or time independently on a given model object property. This method also
1375
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1376
-     *
1377
-     * @access protected
1378
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1379
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1380
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1381
-     *                                        EE_Datetime_Field property)
1382
-     * @throws \EE_Error
1383
-     */
1384
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1385
-    {
1386
-        $field = $this->_get_dtt_field_settings($fieldname);
1387
-        $field->set_timezone($this->_timezone);
1388
-        $field->set_date_format($this->_dt_frmt);
1389
-        $field->set_time_format($this->_tm_frmt);
1390
-        switch ($what) {
1391
-            case 'T' :
1392
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1393
-                    $datetime_value,
1394
-                    $this->_fields[$fieldname]
1395
-                );
1396
-                break;
1397
-            case 'D' :
1398
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1399
-                    $datetime_value,
1400
-                    $this->_fields[$fieldname]
1401
-                );
1402
-                break;
1403
-            case 'B' :
1404
-                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1405
-                break;
1406
-        }
1407
-        $this->_clear_cached_property($fieldname);
1408
-    }
1409
-
1410
-
1411
-
1412
-    /**
1413
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1414
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1415
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1416
-     * that could lead to some unexpected results!
1417
-     *
1418
-     * @access public
1419
-     * @param string               $field_name This is the name of the field on the object that contains the date/time
1420
-     *                                         value being returned.
1421
-     * @param string               $callback   must match a valid method in this class (defaults to get_datetime)
1422
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1423
-     * @param string               $prepend    You can include something to prepend on the timestamp
1424
-     * @param string               $append     You can include something to append on the timestamp
1425
-     * @throws EE_Error
1426
-     * @return string timestamp
1427
-     */
1428
-    public function display_in_my_timezone(
1429
-        $field_name,
1430
-        $callback = 'get_datetime',
1431
-        $args = null,
1432
-        $prepend = '',
1433
-        $append = ''
1434
-    ) {
1435
-        $timezone = EEH_DTT_Helper::get_timezone();
1436
-        if ($timezone === $this->_timezone) {
1437
-            return '';
1438
-        }
1439
-        $original_timezone = $this->_timezone;
1440
-        $this->set_timezone($timezone);
1441
-        $fn = (array)$field_name;
1442
-        $args = array_merge($fn, (array)$args);
1443
-        if ( ! method_exists($this, $callback)) {
1444
-            throw new EE_Error(
1445
-                sprintf(
1446
-                    __(
1447
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1448
-                        'event_espresso'
1449
-                    ),
1450
-                    $callback
1451
-                )
1452
-            );
1453
-        }
1454
-        $args = (array)$args;
1455
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1456
-        $this->set_timezone($original_timezone);
1457
-        return $return;
1458
-    }
1459
-
1460
-
1461
-
1462
-    /**
1463
-     * Deletes this model object.
1464
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1465
-     * override
1466
-     * `EE_Base_Class::_delete` NOT this class.
1467
-     *
1468
-     * @return boolean | int
1469
-     * @throws \EE_Error
1470
-     */
1471
-    public function delete()
1472
-    {
1473
-        /**
1474
-         * Called just before the `EE_Base_Class::_delete` method call.
1475
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1476
-         * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1477
-         * soft deletes (trash) the object and does not permanently delete it.
1478
-         *
1479
-         * @param EE_Base_Class $model_object about to be 'deleted'
1480
-         */
1481
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1482
-        $result = $this->_delete();
1483
-        /**
1484
-         * Called just after the `EE_Base_Class::_delete` method call.
1485
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1486
-         * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1487
-         * soft deletes (trash) the object and does not permanently delete it.
1488
-         *
1489
-         * @param EE_Base_Class $model_object that was just 'deleted'
1490
-         * @param boolean       $result
1491
-         */
1492
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1493
-        return $result;
1494
-    }
1495
-
1496
-
1497
-
1498
-    /**
1499
-     * Calls the specific delete method for the instantiated class.
1500
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1501
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1502
-     * `EE_Base_Class::delete`
1503
-     *
1504
-     * @return bool|int
1505
-     * @throws \EE_Error
1506
-     */
1507
-    protected function _delete()
1508
-    {
1509
-        return $this->delete_permanently();
1510
-    }
1511
-
1512
-
1513
-
1514
-    /**
1515
-     * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1516
-     * error)
1517
-     *
1518
-     * @return bool | int
1519
-     * @throws \EE_Error
1520
-     */
1521
-    public function delete_permanently()
1522
-    {
1523
-        /**
1524
-         * Called just before HARD deleting a model object
1525
-         *
1526
-         * @param EE_Base_Class $model_object about to be 'deleted'
1527
-         */
1528
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1529
-        $model = $this->get_model();
1530
-        $result = $model->delete_permanently_by_ID($this->ID());
1531
-        $this->refresh_cache_of_related_objects();
1532
-        /**
1533
-         * Called just after HARD deleting a model object
1534
-         *
1535
-         * @param EE_Base_Class $model_object that was just 'deleted'
1536
-         * @param boolean       $result
1537
-         */
1538
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1539
-        return $result;
1540
-    }
1541
-
1542
-
1543
-
1544
-    /**
1545
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1546
-     * related model objects
1547
-     *
1548
-     * @throws \EE_Error
1549
-     */
1550
-    public function refresh_cache_of_related_objects()
1551
-    {
1552
-        $model = $this->get_model();
1553
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1554
-            if ( ! empty($this->_model_relations[$relation_name])) {
1555
-                $related_objects = $this->_model_relations[$relation_name];
1556
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1557
-                    //this relation only stores a single model object, not an array
1558
-                    //but let's make it consistent
1559
-                    $related_objects = array($related_objects);
1560
-                }
1561
-                foreach ($related_objects as $related_object) {
1562
-                    //only refresh their cache if they're in memory
1563
-                    if ($related_object instanceof EE_Base_Class) {
1564
-                        $related_object->clear_cache($model->get_this_model_name(), $this);
1565
-                    }
1566
-                }
1567
-            }
1568
-        }
1569
-    }
1570
-
1571
-
1572
-
1573
-    /**
1574
-     *        Saves this object to the database. An array may be supplied to set some values on this
1575
-     * object just before saving.
1576
-     *
1577
-     * @access public
1578
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1579
-     *                                 if provided during the save() method (often client code will change the fields'
1580
-     *                                 values before calling save)
1581
-     * @throws \EE_Error
1582
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1583
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1584
-     */
1585
-    public function save($set_cols_n_values = array())
1586
-    {
1587
-        $model = $this->get_model();
1588
-        /**
1589
-         * Filters the fields we're about to save on the model object
1590
-         *
1591
-         * @param array         $set_cols_n_values
1592
-         * @param EE_Base_Class $model_object
1593
-         */
1594
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1595
-            $this);
1596
-        //set attributes as provided in $set_cols_n_values
1597
-        foreach ($set_cols_n_values as $column => $value) {
1598
-            $this->set($column, $value);
1599
-        }
1600
-        // no changes ? then don't do anything
1601
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1602
-            return 0;
1603
-        }
1604
-        /**
1605
-         * Saving a model object.
1606
-         * Before we perform a save, this action is fired.
1607
-         *
1608
-         * @param EE_Base_Class $model_object the model object about to be saved.
1609
-         */
1610
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1611
-        if ( ! $this->allow_persist()) {
1612
-            return 0;
1613
-        }
1614
-        //now get current attribute values
1615
-        $save_cols_n_values = $this->_fields;
1616
-        //if the object already has an ID, update it. Otherwise, insert it
1617
-        //also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1618
-        $old_assumption_concerning_value_preparation = $model
1619
-                                                            ->get_assumption_concerning_values_already_prepared_by_model_object();
1620
-        $model->assume_values_already_prepared_by_model_object(true);
1621
-        //does this model have an autoincrement PK?
1622
-        if ($model->has_primary_key_field()) {
1623
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1624
-                //ok check if it's set, if so: update; if not, insert
1625
-                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1626
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1627
-                } else {
1628
-                    unset($save_cols_n_values[$model->primary_key_name()]);
1629
-                    $results = $model->insert($save_cols_n_values);
1630
-                    if ($results) {
1631
-                        //if successful, set the primary key
1632
-                        //but don't use the normal SET method, because it will check if
1633
-                        //an item with the same ID exists in the mapper & db, then
1634
-                        //will find it in the db (because we just added it) and THAT object
1635
-                        //will get added to the mapper before we can add this one!
1636
-                        //but if we just avoid using the SET method, all that headache can be avoided
1637
-                        $pk_field_name = $model->primary_key_name();
1638
-                        $this->_fields[$pk_field_name] = $results;
1639
-                        $this->_clear_cached_property($pk_field_name);
1640
-                        $model->add_to_entity_map($this);
1641
-                        $this->_update_cached_related_model_objs_fks();
1642
-                    }
1643
-                }
1644
-            } else {//PK is NOT auto-increment
1645
-                //so check if one like it already exists in the db
1646
-                if ($model->exists_by_ID($this->ID())) {
1647
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1648
-                        throw new EE_Error(
1649
-                            sprintf(
1650
-                                __('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1651
-                                    'event_espresso'),
1652
-                                get_class($this),
1653
-                                get_class($model) . '::instance()->add_to_entity_map()',
1654
-                                get_class($model) . '::instance()->get_one_by_ID()',
1655
-                                '<br />'
1656
-                            )
1657
-                        );
1658
-                    }
1659
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1660
-                } else {
1661
-                    $results = $model->insert($save_cols_n_values);
1662
-                    $this->_update_cached_related_model_objs_fks();
1663
-                }
1664
-            }
1665
-        } else {//there is NO primary key
1666
-            $already_in_db = false;
1667
-            foreach ($model->unique_indexes() as $index) {
1668
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1669
-                if ($model->exists(array($uniqueness_where_params))) {
1670
-                    $already_in_db = true;
1671
-                }
1672
-            }
1673
-            if ($already_in_db) {
1674
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1675
-                    $model->get_combined_primary_key_fields());
1676
-                $results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1677
-            } else {
1678
-                $results = $model->insert($save_cols_n_values);
1679
-            }
1680
-        }
1681
-        //restore the old assumption about values being prepared by the model object
1682
-        $model
1683
-             ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1684
-        /**
1685
-         * After saving the model object this action is called
1686
-         *
1687
-         * @param EE_Base_Class $model_object which was just saved
1688
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1689
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1690
-         */
1691
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1692
-        $this->_has_changes = false;
1693
-        return $results;
1694
-    }
1695
-
1696
-
1697
-
1698
-    /**
1699
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1700
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1701
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1702
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1703
-     * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1704
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1705
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1706
-     *
1707
-     * @return void
1708
-     * @throws \EE_Error
1709
-     */
1710
-    protected function _update_cached_related_model_objs_fks()
1711
-    {
1712
-        $model = $this->get_model();
1713
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1714
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1715
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1716
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1717
-                        $model->get_this_model_name()
1718
-                    );
1719
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1720
-                    if ($related_model_obj_in_cache->ID()) {
1721
-                        $related_model_obj_in_cache->save();
1722
-                    }
1723
-                }
1724
-            }
1725
-        }
1726
-    }
1727
-
1728
-
1729
-
1730
-    /**
1731
-     * Saves this model object and its NEW cached relations to the database.
1732
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1733
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1734
-     * because otherwise, there's a potential for infinite looping of saving
1735
-     * Saves the cached related model objects, and ensures the relation between them
1736
-     * and this object and properly setup
1737
-     *
1738
-     * @return int ID of new model object on save; 0 on failure+
1739
-     * @throws \EE_Error
1740
-     */
1741
-    public function save_new_cached_related_model_objs()
1742
-    {
1743
-        //make sure this has been saved
1744
-        if ( ! $this->ID()) {
1745
-            $id = $this->save();
1746
-        } else {
1747
-            $id = $this->ID();
1748
-        }
1749
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1750
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1751
-            if ($this->_model_relations[$relationName]) {
1752
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1753
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1754
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1755
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1756
-                    //but ONLY if it DOES NOT exist in the DB
1757
-                    /* @var $related_model_obj EE_Base_Class */
1758
-                    $related_model_obj = $this->_model_relations[$relationName];
1759
-                    //					if( ! $related_model_obj->ID()){
1760
-                    $this->_add_relation_to($related_model_obj, $relationName);
1761
-                    $related_model_obj->save_new_cached_related_model_objs();
1762
-                    //					}
1763
-                } else {
1764
-                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1765
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
1766
-                        //but ONLY if it DOES NOT exist in the DB
1767
-                        //						if( ! $related_model_obj->ID()){
1768
-                        $this->_add_relation_to($related_model_obj, $relationName);
1769
-                        $related_model_obj->save_new_cached_related_model_objs();
1770
-                        //						}
1771
-                    }
1772
-                }
1773
-            }
1774
-        }
1775
-        return $id;
1776
-    }
1777
-
1778
-
1779
-
1780
-    /**
1781
-     * for getting a model while instantiated.
1782
-     *
1783
-     * @return \EEM_Base | \EEM_CPT_Base
1784
-     */
1785
-    public function get_model()
1786
-    {
1787
-        if( ! $this->_model){
1788
-            $modelName = self::_get_model_classname(get_class($this));
1789
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1790
-        } else {
1791
-            $this->_model->set_timezone($this->_timezone);
1792
-        }
1793
-
1794
-        return $this->_model;
1795
-    }
1796
-
1797
-
1798
-
1799
-    /**
1800
-     * @param $props_n_values
1801
-     * @param $classname
1802
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1803
-     * @throws \EE_Error
1804
-     */
1805
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1806
-    {
1807
-        //TODO: will not work for Term_Relationships because they have no PK!
1808
-        $primary_id_ref = self::_get_primary_key_name($classname);
1809
-        if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1810
-            $id = $props_n_values[$primary_id_ref];
1811
-            return self::_get_model($classname)->get_from_entity_map($id);
1812
-        }
1813
-        return false;
1814
-    }
1815
-
1816
-
1817
-
1818
-    /**
1819
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1820
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1821
-     * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
1822
-     * we return false.
1823
-     *
1824
-     * @param  array  $props_n_values   incoming array of properties and their values
1825
-     * @param  string $classname        the classname of the child class
1826
-     * @param null    $timezone
1827
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
1828
-     *                                  date_format and the second value is the time format
1829
-     * @return mixed (EE_Base_Class|bool)
1830
-     * @throws \EE_Error
1831
-     */
1832
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1833
-    {
1834
-        $existing = null;
1835
-        $model = self::_get_model($classname, $timezone);
1836
-        if ($model->has_primary_key_field()) {
1837
-            $primary_id_ref = self::_get_primary_key_name($classname);
1838
-            if (array_key_exists($primary_id_ref, $props_n_values)
1839
-                && ! empty($props_n_values[$primary_id_ref])
1840
-            ) {
1841
-                $existing = $model->get_one_by_ID(
1842
-                    $props_n_values[$primary_id_ref]
1843
-                );
1844
-            }
1845
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1846
-            //no primary key on this model, but there's still a matching item in the DB
1847
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1848
-                self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1849
-            );
1850
-        }
1851
-        if ($existing) {
1852
-            //set date formats if present before setting values
1853
-            if ( ! empty($date_formats) && is_array($date_formats)) {
1854
-                $existing->set_date_format($date_formats[0]);
1855
-                $existing->set_time_format($date_formats[1]);
1856
-            } else {
1857
-                //set default formats for date and time
1858
-                $existing->set_date_format(get_option('date_format'));
1859
-                $existing->set_time_format(get_option('time_format'));
1860
-            }
1861
-            foreach ($props_n_values as $property => $field_value) {
1862
-                $existing->set($property, $field_value);
1863
-            }
1864
-            return $existing;
1865
-        } else {
1866
-            return false;
1867
-        }
1868
-    }
1869
-
1870
-
1871
-
1872
-    /**
1873
-     * Gets the EEM_*_Model for this class
1874
-     *
1875
-     * @access public now, as this is more convenient
1876
-     * @param      $classname
1877
-     * @param null $timezone
1878
-     * @throws EE_Error
1879
-     * @return EEM_Base
1880
-     */
1881
-    protected static function _get_model($classname, $timezone = null)
1882
-    {
1883
-        //find model for this class
1884
-        if ( ! $classname) {
1885
-            throw new EE_Error(
1886
-                sprintf(
1887
-                    __(
1888
-                        "What were you thinking calling _get_model(%s)?? You need to specify the class name",
1889
-                        "event_espresso"
1890
-                    ),
1891
-                    $classname
1892
-                )
1893
-            );
1894
-        }
1895
-        $modelName = self::_get_model_classname($classname);
1896
-        return self::_get_model_instance_with_name($modelName, $timezone);
1897
-    }
1898
-
1899
-
1900
-
1901
-    /**
1902
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1903
-     *
1904
-     * @param string $model_classname
1905
-     * @param null   $timezone
1906
-     * @return EEM_Base
1907
-     */
1908
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1909
-    {
1910
-        $model_classname = str_replace('EEM_', '', $model_classname);
1911
-        $model = EE_Registry::instance()->load_model($model_classname);
1912
-        $model->set_timezone($timezone);
1913
-        return $model;
1914
-    }
1915
-
1916
-
1917
-
1918
-    /**
1919
-     * If a model name is provided (eg Registration), gets the model classname for that model.
1920
-     * Also works if a model class's classname is provided (eg EE_Registration).
1921
-     *
1922
-     * @param null $model_name
1923
-     * @return string like EEM_Attendee
1924
-     */
1925
-    private static function _get_model_classname($model_name = null)
1926
-    {
1927
-        if (strpos($model_name, "EE_") === 0) {
1928
-            $model_classname = str_replace("EE_", "EEM_", $model_name);
1929
-        } else {
1930
-            $model_classname = "EEM_" . $model_name;
1931
-        }
1932
-        return $model_classname;
1933
-    }
1934
-
1935
-
1936
-
1937
-    /**
1938
-     * returns the name of the primary key attribute
1939
-     *
1940
-     * @param null $classname
1941
-     * @throws EE_Error
1942
-     * @return string
1943
-     */
1944
-    protected static function _get_primary_key_name($classname = null)
1945
-    {
1946
-        if ( ! $classname) {
1947
-            throw new EE_Error(
1948
-                sprintf(
1949
-                    __("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
1950
-                    $classname
1951
-                )
1952
-            );
1953
-        }
1954
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
1955
-    }
1956
-
1957
-
1958
-
1959
-    /**
1960
-     * Gets the value of the primary key.
1961
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
1962
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
1963
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
1964
-     *
1965
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
1966
-     * @throws \EE_Error
1967
-     */
1968
-    public function ID()
1969
-    {
1970
-        $model = $this->get_model();
1971
-        //now that we know the name of the variable, use a variable variable to get its value and return its
1972
-        if ($model->has_primary_key_field()) {
1973
-            return $this->_fields[$model->primary_key_name()];
1974
-        } else {
1975
-            return $model->get_index_primary_key_string($this->_fields);
1976
-        }
1977
-    }
1978
-
1979
-
1980
-
1981
-    /**
1982
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
1983
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
1984
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
1985
-     *
1986
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
1987
-     * @param string $relationName                     eg 'Events','Question',etc.
1988
-     *                                                 an attendee to a group, you also want to specify which role they
1989
-     *                                                 will have in that group. So you would use this parameter to
1990
-     *                                                 specify array('role-column-name'=>'role-id')
1991
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
1992
-     *                                                 allow you to further constrict the relation to being added.
1993
-     *                                                 However, keep in mind that the columns (keys) given must match a
1994
-     *                                                 column on the JOIN table and currently only the HABTM models
1995
-     *                                                 accept these additional conditions.  Also remember that if an
1996
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
1997
-     *                                                 NEW row is created in the join table.
1998
-     * @param null   $cache_id
1999
-     * @throws EE_Error
2000
-     * @return EE_Base_Class the object the relation was added to
2001
-     */
2002
-    public function _add_relation_to(
2003
-        $otherObjectModelObjectOrID,
2004
-        $relationName,
2005
-        $extra_join_model_fields_n_values = array(),
2006
-        $cache_id = null
2007
-    ) {
2008
-        $model = $this->get_model();
2009
-        //if this thing exists in the DB, save the relation to the DB
2010
-        if ($this->ID()) {
2011
-            $otherObject = $model
2012
-                                ->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2013
-                                    $extra_join_model_fields_n_values);
2014
-            //clear cache so future get_many_related and get_first_related() return new results.
2015
-            $this->clear_cache($relationName, $otherObject, true);
2016
-            if ($otherObject instanceof EE_Base_Class) {
2017
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2018
-            }
2019
-        } else {
2020
-            //this thing doesn't exist in the DB,  so just cache it
2021
-            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2022
-                throw new EE_Error(sprintf(
2023
-                    __('Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2024
-                        'event_espresso'),
2025
-                    $otherObjectModelObjectOrID,
2026
-                    get_class($this)
2027
-                ));
2028
-            } else {
2029
-                $otherObject = $otherObjectModelObjectOrID;
2030
-            }
2031
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2032
-        }
2033
-        if ($otherObject instanceof EE_Base_Class) {
2034
-            //fix the reciprocal relation too
2035
-            if ($otherObject->ID()) {
2036
-                //its saved so assumed relations exist in the DB, so we can just
2037
-                //clear the cache so future queries use the updated info in the DB
2038
-                $otherObject->clear_cache($model->get_this_model_name(), null, true);
2039
-            } else {
2040
-                //it's not saved, so it caches relations like this
2041
-                $otherObject->cache($model->get_this_model_name(), $this);
2042
-            }
2043
-        }
2044
-        return $otherObject;
2045
-    }
2046
-
2047
-
2048
-
2049
-    /**
2050
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2051
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2052
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2053
-     * from the cache
2054
-     *
2055
-     * @param mixed  $otherObjectModelObjectOrID
2056
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2057
-     *                to the DB yet
2058
-     * @param string $relationName
2059
-     * @param array  $where_query
2060
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2061
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2062
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2063
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2064
-     *                created in the join table.
2065
-     * @return EE_Base_Class the relation was removed from
2066
-     * @throws \EE_Error
2067
-     */
2068
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2069
-    {
2070
-        if ($this->ID()) {
2071
-            //if this exists in the DB, save the relation change to the DB too
2072
-            $otherObject = $this->get_model()
2073
-                                ->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2074
-                                    $where_query);
2075
-            $this->clear_cache($relationName, $otherObject);
2076
-        } else {
2077
-            //this doesn't exist in the DB, just remove it from the cache
2078
-            $otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2079
-        }
2080
-        if ($otherObject instanceof EE_Base_Class) {
2081
-            $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2082
-        }
2083
-        return $otherObject;
2084
-    }
2085
-
2086
-
2087
-
2088
-    /**
2089
-     * Removes ALL the related things for the $relationName.
2090
-     *
2091
-     * @param string $relationName
2092
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2093
-     * @return EE_Base_Class
2094
-     * @throws \EE_Error
2095
-     */
2096
-    public function _remove_relations($relationName, $where_query_params = array())
2097
-    {
2098
-        if ($this->ID()) {
2099
-            //if this exists in the DB, save the relation change to the DB too
2100
-            $otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2101
-            $this->clear_cache($relationName, null, true);
2102
-        } else {
2103
-            //this doesn't exist in the DB, just remove it from the cache
2104
-            $otherObjects = $this->clear_cache($relationName, null, true);
2105
-        }
2106
-        if (is_array($otherObjects)) {
2107
-            foreach ($otherObjects as $otherObject) {
2108
-                $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2109
-            }
2110
-        }
2111
-        return $otherObjects;
2112
-    }
2113
-
2114
-
2115
-
2116
-    /**
2117
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2118
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2119
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2120
-     * because we want to get even deleted items etc.
2121
-     *
2122
-     * @param string $relationName key in the model's _model_relations array
2123
-     * @param array  $query_params like EEM_Base::get_all
2124
-     * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2125
-     * @throws \EE_Error
2126
-     *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2127
-     *                             you want IDs
2128
-     */
2129
-    public function get_many_related($relationName, $query_params = array())
2130
-    {
2131
-        if ($this->ID()) {
2132
-            //this exists in the DB, so get the related things from either the cache or the DB
2133
-            //if there are query parameters, forget about caching the related model objects.
2134
-            if ($query_params) {
2135
-                $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2136
-            } else {
2137
-                //did we already cache the result of this query?
2138
-                $cached_results = $this->get_all_from_cache($relationName);
2139
-                if ( ! $cached_results) {
2140
-                    $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2141
-                    //if no query parameters were passed, then we got all the related model objects
2142
-                    //for that relation. We can cache them then.
2143
-                    foreach ($related_model_objects as $related_model_object) {
2144
-                        $this->cache($relationName, $related_model_object);
2145
-                    }
2146
-                } else {
2147
-                    $related_model_objects = $cached_results;
2148
-                }
2149
-            }
2150
-        } else {
2151
-            //this doesn't exist in the DB, so just get the related things from the cache
2152
-            $related_model_objects = $this->get_all_from_cache($relationName);
2153
-        }
2154
-        return $related_model_objects;
2155
-    }
2156
-
2157
-
2158
-
2159
-    /**
2160
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2161
-     * unless otherwise specified in the $query_params
2162
-     *
2163
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2164
-     * @param array  $query_params   like EEM_Base::get_all's
2165
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2166
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2167
-     *                               that by the setting $distinct to TRUE;
2168
-     * @return int
2169
-     */
2170
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2171
-    {
2172
-        return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2173
-    }
2174
-
2175
-
2176
-
2177
-    /**
2178
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2179
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2180
-     *
2181
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2182
-     * @param array  $query_params  like EEM_Base::get_all's
2183
-     * @param string $field_to_sum  name of field to count by.
2184
-     *                              By default, uses primary key (which doesn't make much sense, so you should probably
2185
-     *                              change it)
2186
-     * @return int
2187
-     */
2188
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2189
-    {
2190
-        return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2191
-    }
2192
-
2193
-
2194
-
2195
-    /**
2196
-     * Gets the first (ie, one) related model object of the specified type.
2197
-     *
2198
-     * @param string $relationName key in the model's _model_relations array
2199
-     * @param array  $query_params like EEM_Base::get_all
2200
-     * @return EE_Base_Class (not an array, a single object)
2201
-     * @throws \EE_Error
2202
-     */
2203
-    public function get_first_related($relationName, $query_params = array())
2204
-    {
2205
-        $model = $this->get_model();
2206
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2207
-            //if they've provided some query parameters, don't bother trying to cache the result
2208
-            //also make sure we're not caching the result of get_first_related
2209
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2210
-            if ($query_params
2211
-                || ! $model->related_settings_for($relationName)
2212
-                     instanceof
2213
-                     EE_Belongs_To_Relation
2214
-            ) {
2215
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2216
-            } else {
2217
-                //first, check if we've already cached the result of this query
2218
-                $cached_result = $this->get_one_from_cache($relationName);
2219
-                if ( ! $cached_result) {
2220
-                    $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2221
-                    $this->cache($relationName, $related_model_object);
2222
-                } else {
2223
-                    $related_model_object = $cached_result;
2224
-                }
2225
-            }
2226
-        } else {
2227
-            $related_model_object = null;
2228
-            //this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2229
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2230
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2231
-            }
2232
-            //this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2233
-            if ( ! $related_model_object) {
2234
-                $related_model_object = $this->get_one_from_cache($relationName);
2235
-            }
2236
-        }
2237
-        return $related_model_object;
2238
-    }
2239
-
2240
-
2241
-
2242
-    /**
2243
-     * Does a delete on all related objects of type $relationName and removes
2244
-     * the current model object's relation to them. If they can't be deleted (because
2245
-     * of blocking related model objects) does nothing. If the related model objects are
2246
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2247
-     * If this model object doesn't exist yet in the DB, just removes its related things
2248
-     *
2249
-     * @param string $relationName
2250
-     * @param array  $query_params like EEM_Base::get_all's
2251
-     * @return int how many deleted
2252
-     * @throws \EE_Error
2253
-     */
2254
-    public function delete_related($relationName, $query_params = array())
2255
-    {
2256
-        if ($this->ID()) {
2257
-            $count = $this->get_model()->delete_related($this, $relationName, $query_params);
2258
-        } else {
2259
-            $count = count($this->get_all_from_cache($relationName));
2260
-            $this->clear_cache($relationName, null, true);
2261
-        }
2262
-        return $count;
2263
-    }
2264
-
2265
-
2266
-
2267
-    /**
2268
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2269
-     * the current model object's relation to them. If they can't be deleted (because
2270
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2271
-     * If the related thing isn't a soft-deletable model object, this function is identical
2272
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2273
-     *
2274
-     * @param string $relationName
2275
-     * @param array  $query_params like EEM_Base::get_all's
2276
-     * @return int how many deleted (including those soft deleted)
2277
-     * @throws \EE_Error
2278
-     */
2279
-    public function delete_related_permanently($relationName, $query_params = array())
2280
-    {
2281
-        if ($this->ID()) {
2282
-            $count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2283
-        } else {
2284
-            $count = count($this->get_all_from_cache($relationName));
2285
-        }
2286
-        $this->clear_cache($relationName, null, true);
2287
-        return $count;
2288
-    }
2289
-
2290
-
2291
-
2292
-    /**
2293
-     * is_set
2294
-     * Just a simple utility function children can use for checking if property exists
2295
-     *
2296
-     * @access  public
2297
-     * @param  string $field_name property to check
2298
-     * @return bool                              TRUE if existing,FALSE if not.
2299
-     */
2300
-    public function is_set($field_name)
2301
-    {
2302
-        return isset($this->_fields[$field_name]);
2303
-    }
2304
-
2305
-
2306
-
2307
-    /**
2308
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2309
-     * EE_Error exception if they don't
2310
-     *
2311
-     * @param  mixed (string|array) $properties properties to check
2312
-     * @throws EE_Error
2313
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2314
-     */
2315
-    protected function _property_exists($properties)
2316
-    {
2317
-        foreach ((array)$properties as $property_name) {
2318
-            //first make sure this property exists
2319
-            if ( ! $this->_fields[$property_name]) {
2320
-                throw new EE_Error(
2321
-                    sprintf(
2322
-                        __(
2323
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2324
-                            'event_espresso'
2325
-                        ),
2326
-                        $property_name
2327
-                    )
2328
-                );
2329
-            }
2330
-        }
2331
-        return true;
2332
-    }
2333
-
2334
-
2335
-
2336
-    /**
2337
-     * This simply returns an array of model fields for this object
2338
-     *
2339
-     * @return array
2340
-     * @throws \EE_Error
2341
-     */
2342
-    public function model_field_array()
2343
-    {
2344
-        $fields = $this->get_model()->field_settings(false);
2345
-        $properties = array();
2346
-        //remove prepended underscore
2347
-        foreach ($fields as $field_name => $settings) {
2348
-            $properties[$field_name] = $this->get($field_name);
2349
-        }
2350
-        return $properties;
2351
-    }
2352
-
2353
-
2354
-
2355
-    /**
2356
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2357
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2358
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2359
-     * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2360
-     * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2361
-     * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2362
-     * was called, and an array of the original arguments passed to the function. Whatever their callback function
2363
-     * returns will be returned by this function. Example: in functions.php (or in a plugin):
2364
-     * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2365
-     * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2366
-     * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2367
-     *        return $previousReturnValue.$returnString;
2368
-     * }
2369
-     * require('EE_Answer.class.php');
2370
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2371
-     * echo $answer->my_callback('monkeys',100);
2372
-     * //will output "you called my_callback! and passed args:monkeys,100"
2373
-     *
2374
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2375
-     * @param array  $args       array of original arguments passed to the function
2376
-     * @throws EE_Error
2377
-     * @return mixed whatever the plugin which calls add_filter decides
2378
-     */
2379
-    public function __call($methodName, $args)
2380
-    {
2381
-        $className = get_class($this);
2382
-        $tagName = "FHEE__{$className}__{$methodName}";
2383
-        if ( ! has_filter($tagName)) {
2384
-            throw new EE_Error(
2385
-                sprintf(
2386
-                    __(
2387
-                        "Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2388
-                        "event_espresso"
2389
-                    ),
2390
-                    $methodName,
2391
-                    $className,
2392
-                    $tagName
2393
-                )
2394
-            );
2395
-        }
2396
-        return apply_filters($tagName, null, $this, $args);
2397
-    }
2398
-
2399
-
2400
-
2401
-    /**
2402
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2403
-     * A $previous_value can be specified in case there are many meta rows with the same key
2404
-     *
2405
-     * @param string $meta_key
2406
-     * @param mixed  $meta_value
2407
-     * @param mixed  $previous_value
2408
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2409
-     * @throws \EE_Error
2410
-     * NOTE: if the values haven't changed, returns 0
2411
-     */
2412
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2413
-    {
2414
-        $query_params = array(
2415
-            array(
2416
-                'EXM_key'  => $meta_key,
2417
-                'OBJ_ID'   => $this->ID(),
2418
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2419
-            ),
2420
-        );
2421
-        if ($previous_value !== null) {
2422
-            $query_params[0]['EXM_value'] = $meta_value;
2423
-        }
2424
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2425
-        if ( ! $existing_rows_like_that) {
2426
-            return $this->add_extra_meta($meta_key, $meta_value);
2427
-        }
2428
-        foreach ($existing_rows_like_that as $existing_row) {
2429
-            $existing_row->save(array('EXM_value' => $meta_value));
2430
-        }
2431
-        return count($existing_rows_like_that);
2432
-    }
2433
-
2434
-
2435
-
2436
-    /**
2437
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2438
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2439
-     * extra meta row was entered, false if not
2440
-     *
2441
-     * @param string  $meta_key
2442
-     * @param mixed   $meta_value
2443
-     * @param boolean $unique
2444
-     * @return boolean
2445
-     * @throws \EE_Error
2446
-     */
2447
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2448
-    {
2449
-        if ($unique) {
2450
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2451
-                array(
2452
-                    array(
2453
-                        'EXM_key'  => $meta_key,
2454
-                        'OBJ_ID'   => $this->ID(),
2455
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2456
-                    ),
2457
-                )
2458
-            );
2459
-            if ($existing_extra_meta) {
2460
-                return false;
2461
-            }
2462
-        }
2463
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2464
-            array(
2465
-                'EXM_key'   => $meta_key,
2466
-                'EXM_value' => $meta_value,
2467
-                'OBJ_ID'    => $this->ID(),
2468
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2469
-            )
2470
-        );
2471
-        $new_extra_meta->save();
2472
-        return true;
2473
-    }
2474
-
2475
-
2476
-
2477
-    /**
2478
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2479
-     * is specified, only deletes extra meta records with that value.
2480
-     *
2481
-     * @param string $meta_key
2482
-     * @param mixed  $meta_value
2483
-     * @return int number of extra meta rows deleted
2484
-     * @throws \EE_Error
2485
-     */
2486
-    public function delete_extra_meta($meta_key, $meta_value = null)
2487
-    {
2488
-        $query_params = array(
2489
-            array(
2490
-                'EXM_key'  => $meta_key,
2491
-                'OBJ_ID'   => $this->ID(),
2492
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2493
-            ),
2494
-        );
2495
-        if ($meta_value !== null) {
2496
-            $query_params[0]['EXM_value'] = $meta_value;
2497
-        }
2498
-        return EEM_Extra_Meta::instance()->delete($query_params);
2499
-    }
2500
-
2501
-
2502
-
2503
-    /**
2504
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2505
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2506
-     * You can specify $default is case you haven't found the extra meta
2507
-     *
2508
-     * @param string  $meta_key
2509
-     * @param boolean $single
2510
-     * @param mixed   $default if we don't find anything, what should we return?
2511
-     * @return mixed single value if $single; array if ! $single
2512
-     * @throws \EE_Error
2513
-     */
2514
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2515
-    {
2516
-        if ($single) {
2517
-            $result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2518
-            if ($result instanceof EE_Extra_Meta) {
2519
-                return $result->value();
2520
-            } else {
2521
-                return $default;
2522
-            }
2523
-        } else {
2524
-            $results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2525
-            if ($results) {
2526
-                $values = array();
2527
-                foreach ($results as $result) {
2528
-                    if ($result instanceof EE_Extra_Meta) {
2529
-                        $values[$result->ID()] = $result->value();
2530
-                    }
2531
-                }
2532
-                return $values;
2533
-            } else {
2534
-                return $default;
2535
-            }
2536
-        }
2537
-    }
2538
-
2539
-
2540
-
2541
-    /**
2542
-     * Returns a simple array of all the extra meta associated with this model object.
2543
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2544
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2545
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2546
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2547
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2548
-     * finally the extra meta's value as each sub-value. (eg
2549
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2550
-     *
2551
-     * @param boolean $one_of_each_key
2552
-     * @return array
2553
-     * @throws \EE_Error
2554
-     */
2555
-    public function all_extra_meta_array($one_of_each_key = true)
2556
-    {
2557
-        $return_array = array();
2558
-        if ($one_of_each_key) {
2559
-            $extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2560
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2561
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2562
-                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2563
-                }
2564
-            }
2565
-        } else {
2566
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2567
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2568
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2569
-                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2570
-                        $return_array[$extra_meta_obj->key()] = array();
2571
-                    }
2572
-                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2573
-                }
2574
-            }
2575
-        }
2576
-        return $return_array;
2577
-    }
2578
-
2579
-
2580
-
2581
-    /**
2582
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2583
-     *
2584
-     * @return string
2585
-     * @throws \EE_Error
2586
-     */
2587
-    public function name()
2588
-    {
2589
-        //find a field that's not a text field
2590
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2591
-        if ($field_we_can_use) {
2592
-            return $this->get($field_we_can_use->get_name());
2593
-        } else {
2594
-            $first_few_properties = $this->model_field_array();
2595
-            $first_few_properties = array_slice($first_few_properties, 0, 3);
2596
-            $name_parts = array();
2597
-            foreach ($first_few_properties as $name => $value) {
2598
-                $name_parts[] = "$name:$value";
2599
-            }
2600
-            return implode(",", $name_parts);
2601
-        }
2602
-    }
2603
-
2604
-
2605
-
2606
-    /**
2607
-     * in_entity_map
2608
-     * Checks if this model object has been proven to already be in the entity map
2609
-     *
2610
-     * @return boolean
2611
-     * @throws \EE_Error
2612
-     */
2613
-    public function in_entity_map()
2614
-    {
2615
-        if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2616
-            //well, if we looked, did we find it in the entity map?
2617
-            return true;
2618
-        } else {
2619
-            return false;
2620
-        }
2621
-    }
2622
-
2623
-
2624
-
2625
-    /**
2626
-     * refresh_from_db
2627
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
2628
-     *
2629
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2630
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2631
-     */
2632
-    public function refresh_from_db()
2633
-    {
2634
-        if ($this->ID() && $this->in_entity_map()) {
2635
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
2636
-        } else {
2637
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2638
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
2639
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2640
-            //absolutely nothing in it for this ID
2641
-            if (WP_DEBUG) {
2642
-                throw new EE_Error(
2643
-                    sprintf(
2644
-                        __('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2645
-                            'event_espresso'),
2646
-                        $this->ID(),
2647
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2648
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2649
-                    )
2650
-                );
2651
-            }
2652
-        }
2653
-    }
2654
-
2655
-
2656
-
2657
-    /**
2658
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2659
-     * (probably a bad assumption they have made, oh well)
2660
-     *
2661
-     * @return string
2662
-     */
2663
-    public function __toString()
2664
-    {
2665
-        try {
2666
-            return sprintf('%s (%s)', $this->name(), $this->ID());
2667
-        } catch (Exception $e) {
2668
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2669
-            return '';
2670
-        }
2671
-    }
2672
-
2673
-
2674
-
2675
-    /**
2676
-     * Clear related model objects if they're already in the DB, because otherwise when we
2677
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
2678
-     * This means if we have made changes to those related model objects, and want to unserialize
2679
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
2680
-     * Instead, those related model objects should be directly serialized and stored.
2681
-     * Eg, the following won't work:
2682
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2683
-     * $att = $reg->attendee();
2684
-     * $att->set( 'ATT_fname', 'Dirk' );
2685
-     * update_option( 'my_option', serialize( $reg ) );
2686
-     * //END REQUEST
2687
-     * //START NEXT REQUEST
2688
-     * $reg = get_option( 'my_option' );
2689
-     * $reg->attendee()->save();
2690
-     * And would need to be replace with:
2691
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2692
-     * $att = $reg->attendee();
2693
-     * $att->set( 'ATT_fname', 'Dirk' );
2694
-     * update_option( 'my_option', serialize( $reg ) );
2695
-     * //END REQUEST
2696
-     * //START NEXT REQUEST
2697
-     * $att = get_option( 'my_option' );
2698
-     * $att->save();
2699
-     *
2700
-     * @return array
2701
-     * @throws \EE_Error
2702
-     */
2703
-    public function __sleep()
2704
-    {
2705
-        $model = $this->get_model();
2706
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2707
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
2708
-                $classname = 'EE_' . $model->get_this_model_name();
2709
-                if (
2710
-                    $this->get_one_from_cache($relation_name) instanceof $classname
2711
-                    && $this->get_one_from_cache($relation_name)->ID()
2712
-                ) {
2713
-                    $this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2714
-                }
2715
-            }
2716
-        }
2717
-        $this->_props_n_values_provided_in_constructor = array();
2718
-        $properties_to_serialize = get_object_vars($this);
2719
-        //don't serialize the model. It's big and that risks recursion
2720
-        unset($properties_to_serialize['_model']);
2721
-        return array_keys($properties_to_serialize);
2722
-    }
2723
-
2724
-
2725
-
2726
-    /**
2727
-     * restore _props_n_values_provided_in_constructor
2728
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2729
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
2730
-     * At best, you would only be able to detect if state change has occurred during THIS request.
2731
-     */
2732
-    public function __wakeup()
2733
-    {
2734
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
2735
-    }
28
+	/**
29
+	 * This is an array of the original properties and values provided during construction
30
+	 * of this model object. (keys are model field names, values are their values).
31
+	 * This list is important to remember so that when we are merging data from the db, we know
32
+	 * which values to override and which to not override.
33
+	 *
34
+	 * @var array
35
+	 */
36
+	protected $_props_n_values_provided_in_constructor;
37
+
38
+	/**
39
+	 * Timezone
40
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
41
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
42
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
43
+	 * access to it.
44
+	 *
45
+	 * @var string
46
+	 */
47
+	protected $_timezone;
48
+
49
+
50
+
51
+	/**
52
+	 * date format
53
+	 * pattern or format for displaying dates
54
+	 *
55
+	 * @var string $_dt_frmt
56
+	 */
57
+	protected $_dt_frmt;
58
+
59
+
60
+
61
+	/**
62
+	 * time format
63
+	 * pattern or format for displaying time
64
+	 *
65
+	 * @var string $_tm_frmt
66
+	 */
67
+	protected $_tm_frmt;
68
+
69
+
70
+
71
+	/**
72
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
73
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
74
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
75
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
76
+	 *
77
+	 * @var array
78
+	 */
79
+	protected $_cached_properties = array();
80
+
81
+	/**
82
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
83
+	 * single
84
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
85
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
86
+	 * all others have an array)
87
+	 *
88
+	 * @var array
89
+	 */
90
+	protected $_model_relations = array();
91
+
92
+	/**
93
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
94
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
95
+	 *
96
+	 * @var array
97
+	 */
98
+	protected $_fields = array();
99
+
100
+	/**
101
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
102
+	 * For example, we might create model objects intended to only be used for the duration
103
+	 * of this request and to be thrown away, and if they were accidentally saved
104
+	 * it would be a bug.
105
+	 */
106
+	protected $_allow_persist = true;
107
+
108
+	/**
109
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
110
+	 */
111
+	protected $_has_changes = false;
112
+
113
+	/**
114
+	 * @var EEM_Base
115
+	 */
116
+	protected $_model;
117
+
118
+
119
+
120
+	/**
121
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
122
+	 * play nice
123
+	 *
124
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
125
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
126
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
127
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
128
+	 *                                                         corresponding db model or not.
129
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
130
+	 *                                                         be in when instantiating a EE_Base_Class object.
131
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
132
+	 *                                                         value is the date_format and second value is the time
133
+	 *                                                         format.
134
+	 * @throws EE_Error
135
+	 */
136
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
137
+	{
138
+		$className = get_class($this);
139
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
140
+		$model = $this->get_model();
141
+		$model_fields = $model->field_settings(false);
142
+		// ensure $fieldValues is an array
143
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
144
+		// EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
145
+		// verify client code has not passed any invalid field names
146
+		foreach ($fieldValues as $field_name => $field_value) {
147
+			if ( ! isset($model_fields[$field_name])) {
148
+				throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
149
+					"event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
150
+			}
151
+		}
152
+		// EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
153
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
154
+		if ( ! empty($date_formats) && is_array($date_formats)) {
155
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156
+		} else {
157
+			//set default formats for date and time
158
+			$this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
+			$this->_tm_frmt = (string)get_option('time_format', 'g:i a');
160
+		}
161
+		//if db model is instantiating
162
+		if ($bydb) {
163
+			//client code has indicated these field values are from the database
164
+			foreach ($model_fields as $fieldName => $field) {
165
+				$this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
166
+			}
167
+		} else {
168
+			//we're constructing a brand
169
+			//new instance of the model object. Generally, this means we'll need to do more field validation
170
+			foreach ($model_fields as $fieldName => $field) {
171
+				$this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
172
+			}
173
+		}
174
+		//remember what values were passed to this constructor
175
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
176
+		//remember in entity mapper
177
+		if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
178
+			$model->add_to_entity_map($this);
179
+		}
180
+		//setup all the relations
181
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
182
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
183
+				$this->_model_relations[$relation_name] = null;
184
+			} else {
185
+				$this->_model_relations[$relation_name] = array();
186
+			}
187
+		}
188
+		/**
189
+		 * Action done at the end of each model object construction
190
+		 *
191
+		 * @param EE_Base_Class $this the model object just created
192
+		 */
193
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
194
+	}
195
+
196
+
197
+
198
+	/**
199
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
200
+	 *
201
+	 * @return boolean
202
+	 */
203
+	public function allow_persist()
204
+	{
205
+		return $this->_allow_persist;
206
+	}
207
+
208
+
209
+
210
+	/**
211
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
212
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
213
+	 * you got new information that somehow made you change your mind.
214
+	 *
215
+	 * @param boolean $allow_persist
216
+	 * @return boolean
217
+	 */
218
+	public function set_allow_persist($allow_persist)
219
+	{
220
+		return $this->_allow_persist = $allow_persist;
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * Gets the field's original value when this object was constructed during this request.
227
+	 * This can be helpful when determining if a model object has changed or not
228
+	 *
229
+	 * @param string $field_name
230
+	 * @return mixed|null
231
+	 * @throws \EE_Error
232
+	 */
233
+	public function get_original($field_name)
234
+	{
235
+		if (isset($this->_props_n_values_provided_in_constructor[$field_name])
236
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
237
+		) {
238
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
239
+		} else {
240
+			return null;
241
+		}
242
+	}
243
+
244
+
245
+
246
+	/**
247
+	 * @param EE_Base_Class $obj
248
+	 * @return string
249
+	 */
250
+	public function get_class($obj)
251
+	{
252
+		return get_class($obj);
253
+	}
254
+
255
+
256
+
257
+	/**
258
+	 * Overrides parent because parent expects old models.
259
+	 * This also doesn't do any validation, and won't work for serialized arrays
260
+	 *
261
+	 * @param    string $field_name
262
+	 * @param    mixed  $field_value
263
+	 * @param bool      $use_default
264
+	 * @throws \EE_Error
265
+	 */
266
+	public function set($field_name, $field_value, $use_default = false)
267
+	{
268
+		// if not using default and nothing has changed, and object has already been setup (has ID),
269
+		// then don't do anything
270
+		if (
271
+			! $use_default
272
+			&& $this->_fields[$field_name] === $field_value
273
+			&& $this->ID()
274
+		) {
275
+			return;
276
+		}
277
+		$model = $this->get_model();
278
+		$this->_has_changes = true;
279
+		$field_obj = $model->field_settings_for($field_name);
280
+		if ($field_obj instanceof EE_Model_Field_Base) {
281
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
282
+			if ($field_obj instanceof EE_Datetime_Field) {
283
+				$field_obj->set_timezone($this->_timezone);
284
+				$field_obj->set_date_format($this->_dt_frmt);
285
+				$field_obj->set_time_format($this->_tm_frmt);
286
+			}
287
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
288
+			//should the value be null?
289
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
290
+				$this->_fields[$field_name] = $field_obj->get_default_value();
291
+				/**
292
+				 * To save having to refactor all the models, if a default value is used for a
293
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
294
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
295
+				 * object.
296
+				 *
297
+				 * @since 4.6.10+
298
+				 */
299
+				if (
300
+					$field_obj instanceof EE_Datetime_Field
301
+					&& $this->_fields[$field_name] !== null
302
+					&& ! $this->_fields[$field_name] instanceof DateTime
303
+				) {
304
+					empty($this->_fields[$field_name])
305
+						? $this->set($field_name, time())
306
+						: $this->set($field_name, $this->_fields[$field_name]);
307
+				}
308
+			} else {
309
+				$this->_fields[$field_name] = $holder_of_value;
310
+			}
311
+			//if we're not in the constructor...
312
+			//now check if what we set was a primary key
313
+			if (
314
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
315
+				$this->_props_n_values_provided_in_constructor
316
+				&& $field_value
317
+				&& $field_name === $model->primary_key_name()
318
+			) {
319
+				//if so, we want all this object's fields to be filled either with
320
+				//what we've explicitly set on this model
321
+				//or what we have in the db
322
+				// echo "setting primary key!";
323
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
324
+				$obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
325
+				foreach ($fields_on_model as $field_obj) {
326
+					if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
327
+						 && $field_obj->get_name() !== $field_name
328
+					) {
329
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
330
+					}
331
+				}
332
+				//oh this model object has an ID? well make sure its in the entity mapper
333
+				$model->add_to_entity_map($this);
334
+			}
335
+			//let's unset any cache for this field_name from the $_cached_properties property.
336
+			$this->_clear_cached_property($field_name);
337
+		} else {
338
+			throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
339
+				"event_espresso"), $field_name));
340
+		}
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * This sets the field value on the db column if it exists for the given $column_name or
347
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
348
+	 *
349
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
350
+	 * @param string $field_name  Must be the exact column name.
351
+	 * @param mixed  $field_value The value to set.
352
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
353
+	 * @throws \EE_Error
354
+	 */
355
+	public function set_field_or_extra_meta($field_name, $field_value)
356
+	{
357
+		if ($this->get_model()->has_field($field_name)) {
358
+			$this->set($field_name, $field_value);
359
+			return true;
360
+		} else {
361
+			//ensure this object is saved first so that extra meta can be properly related.
362
+			$this->save();
363
+			return $this->update_extra_meta($field_name, $field_value);
364
+		}
365
+	}
366
+
367
+
368
+
369
+	/**
370
+	 * This retrieves the value of the db column set on this class or if that's not present
371
+	 * it will attempt to retrieve from extra_meta if found.
372
+	 * Example Usage:
373
+	 * Via EE_Message child class:
374
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
375
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
376
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
377
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
378
+	 * value for those extra fields dynamically via the EE_message object.
379
+	 *
380
+	 * @param  string $field_name expecting the fully qualified field name.
381
+	 * @return mixed|null  value for the field if found.  null if not found.
382
+	 * @throws \EE_Error
383
+	 */
384
+	public function get_field_or_extra_meta($field_name)
385
+	{
386
+		if ($this->get_model()->has_field($field_name)) {
387
+			$column_value = $this->get($field_name);
388
+		} else {
389
+			//This isn't a column in the main table, let's see if it is in the extra meta.
390
+			$column_value = $this->get_extra_meta($field_name, true, null);
391
+		}
392
+		return $column_value;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
399
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
400
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
401
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
402
+	 *
403
+	 * @access public
404
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
405
+	 * @return void
406
+	 * @throws \EE_Error
407
+	 */
408
+	public function set_timezone($timezone = '')
409
+	{
410
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
411
+		//make sure we clear all cached properties because they won't be relevant now
412
+		$this->_clear_cached_properties();
413
+		//make sure we update field settings and the date for all EE_Datetime_Fields
414
+		$model_fields = $this->get_model()->field_settings(false);
415
+		foreach ($model_fields as $field_name => $field_obj) {
416
+			if ($field_obj instanceof EE_Datetime_Field) {
417
+				$field_obj->set_timezone($this->_timezone);
418
+				if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
419
+					$this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
420
+				}
421
+			}
422
+		}
423
+	}
424
+
425
+
426
+
427
+	/**
428
+	 * This just returns whatever is set for the current timezone.
429
+	 *
430
+	 * @access public
431
+	 * @return string timezone string
432
+	 */
433
+	public function get_timezone()
434
+	{
435
+		return $this->_timezone;
436
+	}
437
+
438
+
439
+
440
+	/**
441
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
442
+	 * internally instead of wp set date format options
443
+	 *
444
+	 * @since 4.6
445
+	 * @param string $format should be a format recognizable by PHP date() functions.
446
+	 */
447
+	public function set_date_format($format)
448
+	{
449
+		$this->_dt_frmt = $format;
450
+		//clear cached_properties because they won't be relevant now.
451
+		$this->_clear_cached_properties();
452
+	}
453
+
454
+
455
+
456
+	/**
457
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
458
+	 * class internally instead of wp set time format options.
459
+	 *
460
+	 * @since 4.6
461
+	 * @param string $format should be a format recognizable by PHP date() functions.
462
+	 */
463
+	public function set_time_format($format)
464
+	{
465
+		$this->_tm_frmt = $format;
466
+		//clear cached_properties because they won't be relevant now.
467
+		$this->_clear_cached_properties();
468
+	}
469
+
470
+
471
+
472
+	/**
473
+	 * This returns the current internal set format for the date and time formats.
474
+	 *
475
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
476
+	 *                             where the first value is the date format and the second value is the time format.
477
+	 * @return mixed string|array
478
+	 */
479
+	public function get_format($full = true)
480
+	{
481
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482
+	}
483
+
484
+
485
+
486
+	/**
487
+	 * cache
488
+	 * stores the passed model object on the current model object.
489
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
490
+	 *
491
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
492
+	 *                                       'Registration' associated with this model object
493
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
494
+	 *                                       that could be a payment or a registration)
495
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
496
+	 *                                       items which will be stored in an array on this object
497
+	 * @throws EE_Error
498
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
499
+	 *                  related thing, no array)
500
+	 */
501
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
502
+	{
503
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
504
+		if ( ! $object_to_cache instanceof EE_Base_Class) {
505
+			return false;
506
+		}
507
+		// also get "how" the object is related, or throw an error
508
+		if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
509
+			throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
510
+				$relationName, get_class($this)));
511
+		}
512
+		// how many things are related ?
513
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
514
+			// if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
515
+			// so for these model objects just set it to be cached
516
+			$this->_model_relations[$relationName] = $object_to_cache;
517
+			$return = true;
518
+		} else {
519
+			// otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
520
+			// eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
521
+			if ( ! is_array($this->_model_relations[$relationName])) {
522
+				// if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
523
+				$this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
524
+					? array($this->_model_relations[$relationName]) : array();
525
+			}
526
+			// first check for a cache_id which is normally empty
527
+			if ( ! empty($cache_id)) {
528
+				// if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
529
+				$this->_model_relations[$relationName][$cache_id] = $object_to_cache;
530
+				$return = $cache_id;
531
+			} elseif ($object_to_cache->ID()) {
532
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
533
+				$this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
534
+				$return = $object_to_cache->ID();
535
+			} else {
536
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
537
+				$this->_model_relations[$relationName][] = $object_to_cache;
538
+				// move the internal pointer to the end of the array
539
+				end($this->_model_relations[$relationName]);
540
+				// and grab the key so that we can return it
541
+				$return = key($this->_model_relations[$relationName]);
542
+			}
543
+		}
544
+		return $return;
545
+	}
546
+
547
+
548
+
549
+	/**
550
+	 * For adding an item to the cached_properties property.
551
+	 *
552
+	 * @access protected
553
+	 * @param string      $fieldname the property item the corresponding value is for.
554
+	 * @param mixed       $value     The value we are caching.
555
+	 * @param string|null $cache_type
556
+	 * @return void
557
+	 * @throws \EE_Error
558
+	 */
559
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
560
+	{
561
+		//first make sure this property exists
562
+		$this->get_model()->field_settings_for($fieldname);
563
+		$cache_type = empty($cache_type) ? 'standard' : $cache_type;
564
+		$this->_cached_properties[$fieldname][$cache_type] = $value;
565
+	}
566
+
567
+
568
+
569
+	/**
570
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
571
+	 * This also SETS the cache if we return the actual property!
572
+	 *
573
+	 * @param string $fieldname        the name of the property we're trying to retrieve
574
+	 * @param bool   $pretty
575
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
576
+	 *                                 (in cases where the same property may be used for different outputs
577
+	 *                                 - i.e. datetime, money etc.)
578
+	 *                                 It can also accept certain pre-defined "schema" strings
579
+	 *                                 to define how to output the property.
580
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
581
+	 * @return mixed                   whatever the value for the property is we're retrieving
582
+	 * @throws \EE_Error
583
+	 */
584
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
585
+	{
586
+		//verify the field exists
587
+		$model = $this->get_model();
588
+		$model->field_settings_for($fieldname);
589
+		$cache_type = $pretty ? 'pretty' : 'standard';
590
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
591
+		if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592
+			return $this->_cached_properties[$fieldname][$cache_type];
593
+		}
594
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
595
+		$this->_set_cached_property($fieldname, $value, $cache_type);
596
+		return $value;
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 * If the cache didn't fetch the needed item, this fetches it.
603
+	 * @param string $fieldname
604
+	 * @param bool $pretty
605
+	 * @param string $extra_cache_ref
606
+	 * @return mixed
607
+	 */
608
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
609
+	{
610
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
611
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
612
+		if ($field_obj instanceof EE_Datetime_Field) {
613
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
614
+		}
615
+		if ( ! isset($this->_fields[$fieldname])) {
616
+			$this->_fields[$fieldname] = null;
617
+		}
618
+		$value = $pretty
619
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
620
+			: $field_obj->prepare_for_get($this->_fields[$fieldname]);
621
+		return $value;
622
+	}
623
+
624
+
625
+
626
+	/**
627
+	 * set timezone, formats, and output for EE_Datetime_Field objects
628
+	 *
629
+	 * @param \EE_Datetime_Field $datetime_field
630
+	 * @param bool               $pretty
631
+	 * @param null $date_or_time
632
+	 * @return void
633
+	 * @throws \EE_Error
634
+	 */
635
+	protected function _prepare_datetime_field(
636
+		EE_Datetime_Field $datetime_field,
637
+		$pretty = false,
638
+		$date_or_time = null
639
+	) {
640
+		$datetime_field->set_timezone($this->_timezone);
641
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
642
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
643
+		//set the output returned
644
+		switch ($date_or_time) {
645
+			case 'D' :
646
+				$datetime_field->set_date_time_output('date');
647
+				break;
648
+			case 'T' :
649
+				$datetime_field->set_date_time_output('time');
650
+				break;
651
+			default :
652
+				$datetime_field->set_date_time_output();
653
+		}
654
+	}
655
+
656
+
657
+
658
+	/**
659
+	 * This just takes care of clearing out the cached_properties
660
+	 *
661
+	 * @return void
662
+	 */
663
+	protected function _clear_cached_properties()
664
+	{
665
+		$this->_cached_properties = array();
666
+	}
667
+
668
+
669
+
670
+	/**
671
+	 * This just clears out ONE property if it exists in the cache
672
+	 *
673
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
674
+	 * @return void
675
+	 */
676
+	protected function _clear_cached_property($property_name)
677
+	{
678
+		if (isset($this->_cached_properties[$property_name])) {
679
+			unset($this->_cached_properties[$property_name]);
680
+		}
681
+	}
682
+
683
+
684
+
685
+	/**
686
+	 * Ensures that this related thing is a model object.
687
+	 *
688
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
689
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
690
+	 * @return EE_Base_Class
691
+	 * @throws \EE_Error
692
+	 */
693
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
694
+	{
695
+		$other_model_instance = self::_get_model_instance_with_name(
696
+			self::_get_model_classname($model_name),
697
+			$this->_timezone
698
+		);
699
+		return $other_model_instance->ensure_is_obj($object_or_id);
700
+	}
701
+
702
+
703
+
704
+	/**
705
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
706
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
707
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
708
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
709
+	 *
710
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
711
+	 *                                                     Eg 'Registration'
712
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
713
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
714
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
715
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
716
+	 *                                                     this is HasMany or HABTM.
717
+	 * @throws EE_Error
718
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
719
+	 *                       relation from all
720
+	 */
721
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
722
+	{
723
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
724
+		$index_in_cache = '';
725
+		if ( ! $relationship_to_model) {
726
+			throw new EE_Error(
727
+				sprintf(
728
+					__("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
729
+					$relationName,
730
+					get_class($this)
731
+				)
732
+			);
733
+		}
734
+		if ($clear_all) {
735
+			$obj_removed = true;
736
+			$this->_model_relations[$relationName] = null;
737
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
738
+			$obj_removed = $this->_model_relations[$relationName];
739
+			$this->_model_relations[$relationName] = null;
740
+		} else {
741
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
742
+				&& $object_to_remove_or_index_into_array->ID()
743
+			) {
744
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
745
+				if (is_array($this->_model_relations[$relationName])
746
+					&& ! isset($this->_model_relations[$relationName][$index_in_cache])
747
+				) {
748
+					$index_found_at = null;
749
+					//find this object in the array even though it has a different key
750
+					foreach ($this->_model_relations[$relationName] as $index => $obj) {
751
+						if (
752
+							$obj instanceof EE_Base_Class
753
+							&& (
754
+								$obj == $object_to_remove_or_index_into_array
755
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
756
+							)
757
+						) {
758
+							$index_found_at = $index;
759
+							break;
760
+						}
761
+					}
762
+					if ($index_found_at) {
763
+						$index_in_cache = $index_found_at;
764
+					} else {
765
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
766
+						//if it wasn't in it to begin with. So we're done
767
+						return $object_to_remove_or_index_into_array;
768
+					}
769
+				}
770
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
771
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
772
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
773
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
774
+						$index_in_cache = $index;
775
+					}
776
+				}
777
+			} else {
778
+				$index_in_cache = $object_to_remove_or_index_into_array;
779
+			}
780
+			//supposedly we've found it. But it could just be that the client code
781
+			//provided a bad index/object
782
+			if (
783
+			isset(
784
+				$this->_model_relations[$relationName],
785
+				$this->_model_relations[$relationName][$index_in_cache]
786
+			)
787
+			) {
788
+				$obj_removed = $this->_model_relations[$relationName][$index_in_cache];
789
+				unset($this->_model_relations[$relationName][$index_in_cache]);
790
+			} else {
791
+				//that thing was never cached anyways.
792
+				$obj_removed = null;
793
+			}
794
+		}
795
+		return $obj_removed;
796
+	}
797
+
798
+
799
+
800
+	/**
801
+	 * update_cache_after_object_save
802
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
803
+	 * obtained after being saved to the db
804
+	 *
805
+	 * @param string         $relationName       - the type of object that is cached
806
+	 * @param \EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
807
+	 * @param string         $current_cache_id   - the ID that was used when originally caching the object
808
+	 * @return boolean TRUE on success, FALSE on fail
809
+	 * @throws \EE_Error
810
+	 */
811
+	public function update_cache_after_object_save(
812
+		$relationName,
813
+		EE_Base_Class $newly_saved_object,
814
+		$current_cache_id = ''
815
+	) {
816
+		// verify that incoming object is of the correct type
817
+		$obj_class = 'EE_' . $relationName;
818
+		if ($newly_saved_object instanceof $obj_class) {
819
+			/* @type EE_Base_Class $newly_saved_object */
820
+			// now get the type of relation
821
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
822
+			// if this is a 1:1 relationship
823
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
824
+				// then just replace the cached object with the newly saved object
825
+				$this->_model_relations[$relationName] = $newly_saved_object;
826
+				return true;
827
+				// or if it's some kind of sordid feral polyamorous relationship...
828
+			} elseif (is_array($this->_model_relations[$relationName])
829
+					  && isset($this->_model_relations[$relationName][$current_cache_id])
830
+			) {
831
+				// then remove the current cached item
832
+				unset($this->_model_relations[$relationName][$current_cache_id]);
833
+				// and cache the newly saved object using it's new ID
834
+				$this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
835
+				return true;
836
+			}
837
+		}
838
+		return false;
839
+	}
840
+
841
+
842
+
843
+	/**
844
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
845
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
846
+	 *
847
+	 * @param string $relationName
848
+	 * @return EE_Base_Class
849
+	 */
850
+	public function get_one_from_cache($relationName)
851
+	{
852
+		$cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
853
+			: null;
854
+		if (is_array($cached_array_or_object)) {
855
+			return array_shift($cached_array_or_object);
856
+		} else {
857
+			return $cached_array_or_object;
858
+		}
859
+	}
860
+
861
+
862
+
863
+	/**
864
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
865
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
866
+	 *
867
+	 * @param string $relationName
868
+	 * @throws \EE_Error
869
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
870
+	 */
871
+	public function get_all_from_cache($relationName)
872
+	{
873
+		$objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
874
+		// if the result is not an array, but exists, make it an array
875
+		$objects = is_array($objects) ? $objects : array($objects);
876
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
877
+		//basically, if this model object was stored in the session, and these cached model objects
878
+		//already have IDs, let's make sure they're in their model's entity mapper
879
+		//otherwise we will have duplicates next time we call
880
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
881
+		$model = EE_Registry::instance()->load_model($relationName);
882
+		foreach ($objects as $model_object) {
883
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
884
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
885
+				if ($model_object->ID()) {
886
+					$model->add_to_entity_map($model_object);
887
+				}
888
+			} else {
889
+				throw new EE_Error(
890
+					sprintf(
891
+						__(
892
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
893
+							'event_espresso'
894
+						),
895
+						$relationName,
896
+						gettype($model_object)
897
+					)
898
+				);
899
+			}
900
+		}
901
+		return $objects;
902
+	}
903
+
904
+
905
+
906
+	/**
907
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
908
+	 * matching the given query conditions.
909
+	 *
910
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
911
+	 * @param int   $limit              How many objects to return.
912
+	 * @param array $query_params       Any additional conditions on the query.
913
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
914
+	 *                                  you can indicate just the columns you want returned
915
+	 * @return array|EE_Base_Class[]
916
+	 * @throws \EE_Error
917
+	 */
918
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
919
+	{
920
+		$model = $this->get_model();
921
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
922
+			? $model->get_primary_key_field()->get_name()
923
+			: $field_to_order_by;
924
+		$current_value = ! empty($field) ? $this->get($field) : null;
925
+		if (empty($field) || empty($current_value)) {
926
+			return array();
927
+		}
928
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
929
+	}
930
+
931
+
932
+
933
+	/**
934
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
935
+	 * matching the given query conditions.
936
+	 *
937
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
938
+	 * @param int   $limit              How many objects to return.
939
+	 * @param array $query_params       Any additional conditions on the query.
940
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
941
+	 *                                  you can indicate just the columns you want returned
942
+	 * @return array|EE_Base_Class[]
943
+	 * @throws \EE_Error
944
+	 */
945
+	public function previous_x(
946
+		$field_to_order_by = null,
947
+		$limit = 1,
948
+		$query_params = array(),
949
+		$columns_to_select = null
950
+	) {
951
+		$model = $this->get_model();
952
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
953
+			? $model->get_primary_key_field()->get_name()
954
+			: $field_to_order_by;
955
+		$current_value = ! empty($field) ? $this->get($field) : null;
956
+		if (empty($field) || empty($current_value)) {
957
+			return array();
958
+		}
959
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
960
+	}
961
+
962
+
963
+
964
+	/**
965
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
966
+	 * matching the given query conditions.
967
+	 *
968
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
969
+	 * @param array $query_params       Any additional conditions on the query.
970
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
971
+	 *                                  you can indicate just the columns you want returned
972
+	 * @return array|EE_Base_Class
973
+	 * @throws \EE_Error
974
+	 */
975
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
976
+	{
977
+		$model = $this->get_model();
978
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
979
+			? $model->get_primary_key_field()->get_name()
980
+			: $field_to_order_by;
981
+		$current_value = ! empty($field) ? $this->get($field) : null;
982
+		if (empty($field) || empty($current_value)) {
983
+			return array();
984
+		}
985
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
986
+	}
987
+
988
+
989
+
990
+	/**
991
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
992
+	 * matching the given query conditions.
993
+	 *
994
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
995
+	 * @param array $query_params       Any additional conditions on the query.
996
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
997
+	 *                                  you can indicate just the column you want returned
998
+	 * @return array|EE_Base_Class
999
+	 * @throws \EE_Error
1000
+	 */
1001
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1002
+	{
1003
+		$model = $this->get_model();
1004
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1005
+			? $model->get_primary_key_field()->get_name()
1006
+			: $field_to_order_by;
1007
+		$current_value = ! empty($field) ? $this->get($field) : null;
1008
+		if (empty($field) || empty($current_value)) {
1009
+			return array();
1010
+		}
1011
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1012
+	}
1013
+
1014
+
1015
+
1016
+	/**
1017
+	 * Overrides parent because parent expects old models.
1018
+	 * This also doesn't do any validation, and won't work for serialized arrays
1019
+	 *
1020
+	 * @param string $field_name
1021
+	 * @param mixed  $field_value_from_db
1022
+	 * @throws \EE_Error
1023
+	 */
1024
+	public function set_from_db($field_name, $field_value_from_db)
1025
+	{
1026
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1027
+		if ($field_obj instanceof EE_Model_Field_Base) {
1028
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1029
+			//eg, a CPT model object could have an entry in the posts table, but no
1030
+			//entry in the meta table. Meaning that all its columns in the meta table
1031
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1032
+			if ($field_value_from_db === null) {
1033
+				if ($field_obj->is_nullable()) {
1034
+					//if the field allows nulls, then let it be null
1035
+					$field_value = null;
1036
+				} else {
1037
+					$field_value = $field_obj->get_default_value();
1038
+				}
1039
+			} else {
1040
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1041
+			}
1042
+			$this->_fields[$field_name] = $field_value;
1043
+			$this->_clear_cached_property($field_name);
1044
+		}
1045
+	}
1046
+
1047
+
1048
+
1049
+	/**
1050
+	 * verifies that the specified field is of the correct type
1051
+	 *
1052
+	 * @param string $field_name
1053
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1054
+	 *                                (in cases where the same property may be used for different outputs
1055
+	 *                                - i.e. datetime, money etc.)
1056
+	 * @return mixed
1057
+	 * @throws \EE_Error
1058
+	 */
1059
+	public function get($field_name, $extra_cache_ref = null)
1060
+	{
1061
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1062
+	}
1063
+
1064
+
1065
+
1066
+	/**
1067
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1068
+	 *
1069
+	 * @param  string $field_name A valid fieldname
1070
+	 * @return mixed              Whatever the raw value stored on the property is.
1071
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1072
+	 */
1073
+	public function get_raw($field_name)
1074
+	{
1075
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1076
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1077
+			? $this->_fields[$field_name]->format('U')
1078
+			: $this->_fields[$field_name];
1079
+	}
1080
+
1081
+
1082
+
1083
+	/**
1084
+	 * This is used to return the internal DateTime object used for a field that is a
1085
+	 * EE_Datetime_Field.
1086
+	 *
1087
+	 * @param string $field_name               The field name retrieving the DateTime object.
1088
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1089
+	 * @throws \EE_Error
1090
+	 *                                         an error is set and false returned.  If the field IS an
1091
+	 *                                         EE_Datetime_Field and but the field value is null, then
1092
+	 *                                         just null is returned (because that indicates that likely
1093
+	 *                                         this field is nullable).
1094
+	 */
1095
+	public function get_DateTime_object($field_name)
1096
+	{
1097
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1098
+		if ( ! $field_settings instanceof EE_Datetime_Field) {
1099
+			EE_Error::add_error(
1100
+				sprintf(
1101
+					__(
1102
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1103
+						'event_espresso'
1104
+					),
1105
+					$field_name
1106
+				),
1107
+				__FILE__,
1108
+				__FUNCTION__,
1109
+				__LINE__
1110
+			);
1111
+			return false;
1112
+		}
1113
+		return $this->_fields[$field_name];
1114
+	}
1115
+
1116
+
1117
+
1118
+	/**
1119
+	 * To be used in template to immediately echo out the value, and format it for output.
1120
+	 * Eg, should call stripslashes and whatnot before echoing
1121
+	 *
1122
+	 * @param string $field_name      the name of the field as it appears in the DB
1123
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1124
+	 *                                (in cases where the same property may be used for different outputs
1125
+	 *                                - i.e. datetime, money etc.)
1126
+	 * @return void
1127
+	 * @throws \EE_Error
1128
+	 */
1129
+	public function e($field_name, $extra_cache_ref = null)
1130
+	{
1131
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1132
+	}
1133
+
1134
+
1135
+
1136
+	/**
1137
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1138
+	 * can be easily used as the value of form input.
1139
+	 *
1140
+	 * @param string $field_name
1141
+	 * @return void
1142
+	 * @throws \EE_Error
1143
+	 */
1144
+	public function f($field_name)
1145
+	{
1146
+		$this->e($field_name, 'form_input');
1147
+	}
1148
+
1149
+
1150
+
1151
+	/**
1152
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1153
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1154
+	 * to see what options are available.
1155
+	 * @param string $field_name
1156
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1157
+	 *                                (in cases where the same property may be used for different outputs
1158
+	 *                                - i.e. datetime, money etc.)
1159
+	 * @return mixed
1160
+	 * @throws \EE_Error
1161
+	 */
1162
+	public function get_pretty($field_name, $extra_cache_ref = null)
1163
+	{
1164
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1165
+	}
1166
+
1167
+
1168
+
1169
+	/**
1170
+	 * This simply returns the datetime for the given field name
1171
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1172
+	 * (and the equivalent e_date, e_time, e_datetime).
1173
+	 *
1174
+	 * @access   protected
1175
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1176
+	 * @param string   $dt_frmt      valid datetime format used for date
1177
+	 *                               (if '' then we just use the default on the field,
1178
+	 *                               if NULL we use the last-used format)
1179
+	 * @param string   $tm_frmt      Same as above except this is for time format
1180
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1181
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1182
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1183
+	 *                               if field is not a valid dtt field, or void if echoing
1184
+	 * @throws \EE_Error
1185
+	 */
1186
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1187
+	{
1188
+		// clear cached property
1189
+		$this->_clear_cached_property($field_name);
1190
+		//reset format properties because they are used in get()
1191
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1192
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1193
+		if ($echo) {
1194
+			$this->e($field_name, $date_or_time);
1195
+			return '';
1196
+		}
1197
+		return $this->get($field_name, $date_or_time);
1198
+	}
1199
+
1200
+
1201
+
1202
+	/**
1203
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1204
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1205
+	 * other echoes the pretty value for dtt)
1206
+	 *
1207
+	 * @param  string $field_name name of model object datetime field holding the value
1208
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1209
+	 * @return string            datetime value formatted
1210
+	 * @throws \EE_Error
1211
+	 */
1212
+	public function get_date($field_name, $format = '')
1213
+	{
1214
+		return $this->_get_datetime($field_name, $format, null, 'D');
1215
+	}
1216
+
1217
+
1218
+
1219
+	/**
1220
+	 * @param      $field_name
1221
+	 * @param string $format
1222
+	 * @throws \EE_Error
1223
+	 */
1224
+	public function e_date($field_name, $format = '')
1225
+	{
1226
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1227
+	}
1228
+
1229
+
1230
+
1231
+	/**
1232
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1233
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1234
+	 * other echoes the pretty value for dtt)
1235
+	 *
1236
+	 * @param  string $field_name name of model object datetime field holding the value
1237
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1238
+	 * @return string             datetime value formatted
1239
+	 * @throws \EE_Error
1240
+	 */
1241
+	public function get_time($field_name, $format = '')
1242
+	{
1243
+		return $this->_get_datetime($field_name, null, $format, 'T');
1244
+	}
1245
+
1246
+
1247
+
1248
+	/**
1249
+	 * @param      $field_name
1250
+	 * @param string $format
1251
+	 * @throws \EE_Error
1252
+	 */
1253
+	public function e_time($field_name, $format = '')
1254
+	{
1255
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1256
+	}
1257
+
1258
+
1259
+
1260
+	/**
1261
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1262
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1263
+	 * other echoes the pretty value for dtt)
1264
+	 *
1265
+	 * @param  string $field_name name of model object datetime field holding the value
1266
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1267
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1268
+	 * @return string             datetime value formatted
1269
+	 * @throws \EE_Error
1270
+	 */
1271
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1272
+	{
1273
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1274
+	}
1275
+
1276
+
1277
+
1278
+	/**
1279
+	 * @param string $field_name
1280
+	 * @param string $dt_frmt
1281
+	 * @param string $tm_frmt
1282
+	 * @throws \EE_Error
1283
+	 */
1284
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1285
+	{
1286
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1287
+	}
1288
+
1289
+
1290
+
1291
+	/**
1292
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1293
+	 *
1294
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1295
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1296
+	 *                           on the object will be used.
1297
+	 * @return string Date and time string in set locale or false if no field exists for the given
1298
+	 * @throws \EE_Error
1299
+	 *                           field name.
1300
+	 */
1301
+	public function get_i18n_datetime($field_name, $format = '')
1302
+	{
1303
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1304
+		return date_i18n(
1305
+			$format,
1306
+			EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1307
+		);
1308
+	}
1309
+
1310
+
1311
+
1312
+	/**
1313
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1314
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1315
+	 * thrown.
1316
+	 *
1317
+	 * @param  string $field_name The field name being checked
1318
+	 * @throws EE_Error
1319
+	 * @return EE_Datetime_Field
1320
+	 */
1321
+	protected function _get_dtt_field_settings($field_name)
1322
+	{
1323
+		$field = $this->get_model()->field_settings_for($field_name);
1324
+		//check if field is dtt
1325
+		if ($field instanceof EE_Datetime_Field) {
1326
+			return $field;
1327
+		} else {
1328
+			throw new EE_Error(sprintf(__('The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1329
+				'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1330
+		}
1331
+	}
1332
+
1333
+
1334
+
1335
+
1336
+	/**
1337
+	 * NOTE ABOUT BELOW:
1338
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1339
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1340
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1341
+	 * method and make sure you send the entire datetime value for setting.
1342
+	 */
1343
+	/**
1344
+	 * sets the time on a datetime property
1345
+	 *
1346
+	 * @access protected
1347
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1348
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1349
+	 * @throws \EE_Error
1350
+	 */
1351
+	protected function _set_time_for($time, $fieldname)
1352
+	{
1353
+		$this->_set_date_time('T', $time, $fieldname);
1354
+	}
1355
+
1356
+
1357
+
1358
+	/**
1359
+	 * sets the date on a datetime property
1360
+	 *
1361
+	 * @access protected
1362
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1363
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1364
+	 * @throws \EE_Error
1365
+	 */
1366
+	protected function _set_date_for($date, $fieldname)
1367
+	{
1368
+		$this->_set_date_time('D', $date, $fieldname);
1369
+	}
1370
+
1371
+
1372
+
1373
+	/**
1374
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1375
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1376
+	 *
1377
+	 * @access protected
1378
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1379
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1380
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1381
+	 *                                        EE_Datetime_Field property)
1382
+	 * @throws \EE_Error
1383
+	 */
1384
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1385
+	{
1386
+		$field = $this->_get_dtt_field_settings($fieldname);
1387
+		$field->set_timezone($this->_timezone);
1388
+		$field->set_date_format($this->_dt_frmt);
1389
+		$field->set_time_format($this->_tm_frmt);
1390
+		switch ($what) {
1391
+			case 'T' :
1392
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1393
+					$datetime_value,
1394
+					$this->_fields[$fieldname]
1395
+				);
1396
+				break;
1397
+			case 'D' :
1398
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1399
+					$datetime_value,
1400
+					$this->_fields[$fieldname]
1401
+				);
1402
+				break;
1403
+			case 'B' :
1404
+				$this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1405
+				break;
1406
+		}
1407
+		$this->_clear_cached_property($fieldname);
1408
+	}
1409
+
1410
+
1411
+
1412
+	/**
1413
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1414
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1415
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1416
+	 * that could lead to some unexpected results!
1417
+	 *
1418
+	 * @access public
1419
+	 * @param string               $field_name This is the name of the field on the object that contains the date/time
1420
+	 *                                         value being returned.
1421
+	 * @param string               $callback   must match a valid method in this class (defaults to get_datetime)
1422
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1423
+	 * @param string               $prepend    You can include something to prepend on the timestamp
1424
+	 * @param string               $append     You can include something to append on the timestamp
1425
+	 * @throws EE_Error
1426
+	 * @return string timestamp
1427
+	 */
1428
+	public function display_in_my_timezone(
1429
+		$field_name,
1430
+		$callback = 'get_datetime',
1431
+		$args = null,
1432
+		$prepend = '',
1433
+		$append = ''
1434
+	) {
1435
+		$timezone = EEH_DTT_Helper::get_timezone();
1436
+		if ($timezone === $this->_timezone) {
1437
+			return '';
1438
+		}
1439
+		$original_timezone = $this->_timezone;
1440
+		$this->set_timezone($timezone);
1441
+		$fn = (array)$field_name;
1442
+		$args = array_merge($fn, (array)$args);
1443
+		if ( ! method_exists($this, $callback)) {
1444
+			throw new EE_Error(
1445
+				sprintf(
1446
+					__(
1447
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1448
+						'event_espresso'
1449
+					),
1450
+					$callback
1451
+				)
1452
+			);
1453
+		}
1454
+		$args = (array)$args;
1455
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1456
+		$this->set_timezone($original_timezone);
1457
+		return $return;
1458
+	}
1459
+
1460
+
1461
+
1462
+	/**
1463
+	 * Deletes this model object.
1464
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1465
+	 * override
1466
+	 * `EE_Base_Class::_delete` NOT this class.
1467
+	 *
1468
+	 * @return boolean | int
1469
+	 * @throws \EE_Error
1470
+	 */
1471
+	public function delete()
1472
+	{
1473
+		/**
1474
+		 * Called just before the `EE_Base_Class::_delete` method call.
1475
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1476
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1477
+		 * soft deletes (trash) the object and does not permanently delete it.
1478
+		 *
1479
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1480
+		 */
1481
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1482
+		$result = $this->_delete();
1483
+		/**
1484
+		 * Called just after the `EE_Base_Class::_delete` method call.
1485
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1486
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1487
+		 * soft deletes (trash) the object and does not permanently delete it.
1488
+		 *
1489
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1490
+		 * @param boolean       $result
1491
+		 */
1492
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1493
+		return $result;
1494
+	}
1495
+
1496
+
1497
+
1498
+	/**
1499
+	 * Calls the specific delete method for the instantiated class.
1500
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1501
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1502
+	 * `EE_Base_Class::delete`
1503
+	 *
1504
+	 * @return bool|int
1505
+	 * @throws \EE_Error
1506
+	 */
1507
+	protected function _delete()
1508
+	{
1509
+		return $this->delete_permanently();
1510
+	}
1511
+
1512
+
1513
+
1514
+	/**
1515
+	 * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1516
+	 * error)
1517
+	 *
1518
+	 * @return bool | int
1519
+	 * @throws \EE_Error
1520
+	 */
1521
+	public function delete_permanently()
1522
+	{
1523
+		/**
1524
+		 * Called just before HARD deleting a model object
1525
+		 *
1526
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1527
+		 */
1528
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1529
+		$model = $this->get_model();
1530
+		$result = $model->delete_permanently_by_ID($this->ID());
1531
+		$this->refresh_cache_of_related_objects();
1532
+		/**
1533
+		 * Called just after HARD deleting a model object
1534
+		 *
1535
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1536
+		 * @param boolean       $result
1537
+		 */
1538
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1539
+		return $result;
1540
+	}
1541
+
1542
+
1543
+
1544
+	/**
1545
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1546
+	 * related model objects
1547
+	 *
1548
+	 * @throws \EE_Error
1549
+	 */
1550
+	public function refresh_cache_of_related_objects()
1551
+	{
1552
+		$model = $this->get_model();
1553
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1554
+			if ( ! empty($this->_model_relations[$relation_name])) {
1555
+				$related_objects = $this->_model_relations[$relation_name];
1556
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1557
+					//this relation only stores a single model object, not an array
1558
+					//but let's make it consistent
1559
+					$related_objects = array($related_objects);
1560
+				}
1561
+				foreach ($related_objects as $related_object) {
1562
+					//only refresh their cache if they're in memory
1563
+					if ($related_object instanceof EE_Base_Class) {
1564
+						$related_object->clear_cache($model->get_this_model_name(), $this);
1565
+					}
1566
+				}
1567
+			}
1568
+		}
1569
+	}
1570
+
1571
+
1572
+
1573
+	/**
1574
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1575
+	 * object just before saving.
1576
+	 *
1577
+	 * @access public
1578
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1579
+	 *                                 if provided during the save() method (often client code will change the fields'
1580
+	 *                                 values before calling save)
1581
+	 * @throws \EE_Error
1582
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1583
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1584
+	 */
1585
+	public function save($set_cols_n_values = array())
1586
+	{
1587
+		$model = $this->get_model();
1588
+		/**
1589
+		 * Filters the fields we're about to save on the model object
1590
+		 *
1591
+		 * @param array         $set_cols_n_values
1592
+		 * @param EE_Base_Class $model_object
1593
+		 */
1594
+		$set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1595
+			$this);
1596
+		//set attributes as provided in $set_cols_n_values
1597
+		foreach ($set_cols_n_values as $column => $value) {
1598
+			$this->set($column, $value);
1599
+		}
1600
+		// no changes ? then don't do anything
1601
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1602
+			return 0;
1603
+		}
1604
+		/**
1605
+		 * Saving a model object.
1606
+		 * Before we perform a save, this action is fired.
1607
+		 *
1608
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1609
+		 */
1610
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1611
+		if ( ! $this->allow_persist()) {
1612
+			return 0;
1613
+		}
1614
+		//now get current attribute values
1615
+		$save_cols_n_values = $this->_fields;
1616
+		//if the object already has an ID, update it. Otherwise, insert it
1617
+		//also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1618
+		$old_assumption_concerning_value_preparation = $model
1619
+															->get_assumption_concerning_values_already_prepared_by_model_object();
1620
+		$model->assume_values_already_prepared_by_model_object(true);
1621
+		//does this model have an autoincrement PK?
1622
+		if ($model->has_primary_key_field()) {
1623
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1624
+				//ok check if it's set, if so: update; if not, insert
1625
+				if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1626
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1627
+				} else {
1628
+					unset($save_cols_n_values[$model->primary_key_name()]);
1629
+					$results = $model->insert($save_cols_n_values);
1630
+					if ($results) {
1631
+						//if successful, set the primary key
1632
+						//but don't use the normal SET method, because it will check if
1633
+						//an item with the same ID exists in the mapper & db, then
1634
+						//will find it in the db (because we just added it) and THAT object
1635
+						//will get added to the mapper before we can add this one!
1636
+						//but if we just avoid using the SET method, all that headache can be avoided
1637
+						$pk_field_name = $model->primary_key_name();
1638
+						$this->_fields[$pk_field_name] = $results;
1639
+						$this->_clear_cached_property($pk_field_name);
1640
+						$model->add_to_entity_map($this);
1641
+						$this->_update_cached_related_model_objs_fks();
1642
+					}
1643
+				}
1644
+			} else {//PK is NOT auto-increment
1645
+				//so check if one like it already exists in the db
1646
+				if ($model->exists_by_ID($this->ID())) {
1647
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1648
+						throw new EE_Error(
1649
+							sprintf(
1650
+								__('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1651
+									'event_espresso'),
1652
+								get_class($this),
1653
+								get_class($model) . '::instance()->add_to_entity_map()',
1654
+								get_class($model) . '::instance()->get_one_by_ID()',
1655
+								'<br />'
1656
+							)
1657
+						);
1658
+					}
1659
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1660
+				} else {
1661
+					$results = $model->insert($save_cols_n_values);
1662
+					$this->_update_cached_related_model_objs_fks();
1663
+				}
1664
+			}
1665
+		} else {//there is NO primary key
1666
+			$already_in_db = false;
1667
+			foreach ($model->unique_indexes() as $index) {
1668
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1669
+				if ($model->exists(array($uniqueness_where_params))) {
1670
+					$already_in_db = true;
1671
+				}
1672
+			}
1673
+			if ($already_in_db) {
1674
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1675
+					$model->get_combined_primary_key_fields());
1676
+				$results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1677
+			} else {
1678
+				$results = $model->insert($save_cols_n_values);
1679
+			}
1680
+		}
1681
+		//restore the old assumption about values being prepared by the model object
1682
+		$model
1683
+			 ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1684
+		/**
1685
+		 * After saving the model object this action is called
1686
+		 *
1687
+		 * @param EE_Base_Class $model_object which was just saved
1688
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1689
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1690
+		 */
1691
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1692
+		$this->_has_changes = false;
1693
+		return $results;
1694
+	}
1695
+
1696
+
1697
+
1698
+	/**
1699
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1700
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1701
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1702
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1703
+	 * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1704
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1705
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1706
+	 *
1707
+	 * @return void
1708
+	 * @throws \EE_Error
1709
+	 */
1710
+	protected function _update_cached_related_model_objs_fks()
1711
+	{
1712
+		$model = $this->get_model();
1713
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1714
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1715
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1716
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1717
+						$model->get_this_model_name()
1718
+					);
1719
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1720
+					if ($related_model_obj_in_cache->ID()) {
1721
+						$related_model_obj_in_cache->save();
1722
+					}
1723
+				}
1724
+			}
1725
+		}
1726
+	}
1727
+
1728
+
1729
+
1730
+	/**
1731
+	 * Saves this model object and its NEW cached relations to the database.
1732
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1733
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1734
+	 * because otherwise, there's a potential for infinite looping of saving
1735
+	 * Saves the cached related model objects, and ensures the relation between them
1736
+	 * and this object and properly setup
1737
+	 *
1738
+	 * @return int ID of new model object on save; 0 on failure+
1739
+	 * @throws \EE_Error
1740
+	 */
1741
+	public function save_new_cached_related_model_objs()
1742
+	{
1743
+		//make sure this has been saved
1744
+		if ( ! $this->ID()) {
1745
+			$id = $this->save();
1746
+		} else {
1747
+			$id = $this->ID();
1748
+		}
1749
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1750
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1751
+			if ($this->_model_relations[$relationName]) {
1752
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1753
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1754
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1755
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1756
+					//but ONLY if it DOES NOT exist in the DB
1757
+					/* @var $related_model_obj EE_Base_Class */
1758
+					$related_model_obj = $this->_model_relations[$relationName];
1759
+					//					if( ! $related_model_obj->ID()){
1760
+					$this->_add_relation_to($related_model_obj, $relationName);
1761
+					$related_model_obj->save_new_cached_related_model_objs();
1762
+					//					}
1763
+				} else {
1764
+					foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1765
+						//add a relation to that relation type (which saves the appropriate thing in the process)
1766
+						//but ONLY if it DOES NOT exist in the DB
1767
+						//						if( ! $related_model_obj->ID()){
1768
+						$this->_add_relation_to($related_model_obj, $relationName);
1769
+						$related_model_obj->save_new_cached_related_model_objs();
1770
+						//						}
1771
+					}
1772
+				}
1773
+			}
1774
+		}
1775
+		return $id;
1776
+	}
1777
+
1778
+
1779
+
1780
+	/**
1781
+	 * for getting a model while instantiated.
1782
+	 *
1783
+	 * @return \EEM_Base | \EEM_CPT_Base
1784
+	 */
1785
+	public function get_model()
1786
+	{
1787
+		if( ! $this->_model){
1788
+			$modelName = self::_get_model_classname(get_class($this));
1789
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1790
+		} else {
1791
+			$this->_model->set_timezone($this->_timezone);
1792
+		}
1793
+
1794
+		return $this->_model;
1795
+	}
1796
+
1797
+
1798
+
1799
+	/**
1800
+	 * @param $props_n_values
1801
+	 * @param $classname
1802
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1803
+	 * @throws \EE_Error
1804
+	 */
1805
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1806
+	{
1807
+		//TODO: will not work for Term_Relationships because they have no PK!
1808
+		$primary_id_ref = self::_get_primary_key_name($classname);
1809
+		if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1810
+			$id = $props_n_values[$primary_id_ref];
1811
+			return self::_get_model($classname)->get_from_entity_map($id);
1812
+		}
1813
+		return false;
1814
+	}
1815
+
1816
+
1817
+
1818
+	/**
1819
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1820
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1821
+	 * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
1822
+	 * we return false.
1823
+	 *
1824
+	 * @param  array  $props_n_values   incoming array of properties and their values
1825
+	 * @param  string $classname        the classname of the child class
1826
+	 * @param null    $timezone
1827
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
1828
+	 *                                  date_format and the second value is the time format
1829
+	 * @return mixed (EE_Base_Class|bool)
1830
+	 * @throws \EE_Error
1831
+	 */
1832
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1833
+	{
1834
+		$existing = null;
1835
+		$model = self::_get_model($classname, $timezone);
1836
+		if ($model->has_primary_key_field()) {
1837
+			$primary_id_ref = self::_get_primary_key_name($classname);
1838
+			if (array_key_exists($primary_id_ref, $props_n_values)
1839
+				&& ! empty($props_n_values[$primary_id_ref])
1840
+			) {
1841
+				$existing = $model->get_one_by_ID(
1842
+					$props_n_values[$primary_id_ref]
1843
+				);
1844
+			}
1845
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1846
+			//no primary key on this model, but there's still a matching item in the DB
1847
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1848
+				self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1849
+			);
1850
+		}
1851
+		if ($existing) {
1852
+			//set date formats if present before setting values
1853
+			if ( ! empty($date_formats) && is_array($date_formats)) {
1854
+				$existing->set_date_format($date_formats[0]);
1855
+				$existing->set_time_format($date_formats[1]);
1856
+			} else {
1857
+				//set default formats for date and time
1858
+				$existing->set_date_format(get_option('date_format'));
1859
+				$existing->set_time_format(get_option('time_format'));
1860
+			}
1861
+			foreach ($props_n_values as $property => $field_value) {
1862
+				$existing->set($property, $field_value);
1863
+			}
1864
+			return $existing;
1865
+		} else {
1866
+			return false;
1867
+		}
1868
+	}
1869
+
1870
+
1871
+
1872
+	/**
1873
+	 * Gets the EEM_*_Model for this class
1874
+	 *
1875
+	 * @access public now, as this is more convenient
1876
+	 * @param      $classname
1877
+	 * @param null $timezone
1878
+	 * @throws EE_Error
1879
+	 * @return EEM_Base
1880
+	 */
1881
+	protected static function _get_model($classname, $timezone = null)
1882
+	{
1883
+		//find model for this class
1884
+		if ( ! $classname) {
1885
+			throw new EE_Error(
1886
+				sprintf(
1887
+					__(
1888
+						"What were you thinking calling _get_model(%s)?? You need to specify the class name",
1889
+						"event_espresso"
1890
+					),
1891
+					$classname
1892
+				)
1893
+			);
1894
+		}
1895
+		$modelName = self::_get_model_classname($classname);
1896
+		return self::_get_model_instance_with_name($modelName, $timezone);
1897
+	}
1898
+
1899
+
1900
+
1901
+	/**
1902
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1903
+	 *
1904
+	 * @param string $model_classname
1905
+	 * @param null   $timezone
1906
+	 * @return EEM_Base
1907
+	 */
1908
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1909
+	{
1910
+		$model_classname = str_replace('EEM_', '', $model_classname);
1911
+		$model = EE_Registry::instance()->load_model($model_classname);
1912
+		$model->set_timezone($timezone);
1913
+		return $model;
1914
+	}
1915
+
1916
+
1917
+
1918
+	/**
1919
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
1920
+	 * Also works if a model class's classname is provided (eg EE_Registration).
1921
+	 *
1922
+	 * @param null $model_name
1923
+	 * @return string like EEM_Attendee
1924
+	 */
1925
+	private static function _get_model_classname($model_name = null)
1926
+	{
1927
+		if (strpos($model_name, "EE_") === 0) {
1928
+			$model_classname = str_replace("EE_", "EEM_", $model_name);
1929
+		} else {
1930
+			$model_classname = "EEM_" . $model_name;
1931
+		}
1932
+		return $model_classname;
1933
+	}
1934
+
1935
+
1936
+
1937
+	/**
1938
+	 * returns the name of the primary key attribute
1939
+	 *
1940
+	 * @param null $classname
1941
+	 * @throws EE_Error
1942
+	 * @return string
1943
+	 */
1944
+	protected static function _get_primary_key_name($classname = null)
1945
+	{
1946
+		if ( ! $classname) {
1947
+			throw new EE_Error(
1948
+				sprintf(
1949
+					__("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
1950
+					$classname
1951
+				)
1952
+			);
1953
+		}
1954
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
1955
+	}
1956
+
1957
+
1958
+
1959
+	/**
1960
+	 * Gets the value of the primary key.
1961
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
1962
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
1963
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
1964
+	 *
1965
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
1966
+	 * @throws \EE_Error
1967
+	 */
1968
+	public function ID()
1969
+	{
1970
+		$model = $this->get_model();
1971
+		//now that we know the name of the variable, use a variable variable to get its value and return its
1972
+		if ($model->has_primary_key_field()) {
1973
+			return $this->_fields[$model->primary_key_name()];
1974
+		} else {
1975
+			return $model->get_index_primary_key_string($this->_fields);
1976
+		}
1977
+	}
1978
+
1979
+
1980
+
1981
+	/**
1982
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
1983
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
1984
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
1985
+	 *
1986
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
1987
+	 * @param string $relationName                     eg 'Events','Question',etc.
1988
+	 *                                                 an attendee to a group, you also want to specify which role they
1989
+	 *                                                 will have in that group. So you would use this parameter to
1990
+	 *                                                 specify array('role-column-name'=>'role-id')
1991
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
1992
+	 *                                                 allow you to further constrict the relation to being added.
1993
+	 *                                                 However, keep in mind that the columns (keys) given must match a
1994
+	 *                                                 column on the JOIN table and currently only the HABTM models
1995
+	 *                                                 accept these additional conditions.  Also remember that if an
1996
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
1997
+	 *                                                 NEW row is created in the join table.
1998
+	 * @param null   $cache_id
1999
+	 * @throws EE_Error
2000
+	 * @return EE_Base_Class the object the relation was added to
2001
+	 */
2002
+	public function _add_relation_to(
2003
+		$otherObjectModelObjectOrID,
2004
+		$relationName,
2005
+		$extra_join_model_fields_n_values = array(),
2006
+		$cache_id = null
2007
+	) {
2008
+		$model = $this->get_model();
2009
+		//if this thing exists in the DB, save the relation to the DB
2010
+		if ($this->ID()) {
2011
+			$otherObject = $model
2012
+								->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2013
+									$extra_join_model_fields_n_values);
2014
+			//clear cache so future get_many_related and get_first_related() return new results.
2015
+			$this->clear_cache($relationName, $otherObject, true);
2016
+			if ($otherObject instanceof EE_Base_Class) {
2017
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2018
+			}
2019
+		} else {
2020
+			//this thing doesn't exist in the DB,  so just cache it
2021
+			if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2022
+				throw new EE_Error(sprintf(
2023
+					__('Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2024
+						'event_espresso'),
2025
+					$otherObjectModelObjectOrID,
2026
+					get_class($this)
2027
+				));
2028
+			} else {
2029
+				$otherObject = $otherObjectModelObjectOrID;
2030
+			}
2031
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2032
+		}
2033
+		if ($otherObject instanceof EE_Base_Class) {
2034
+			//fix the reciprocal relation too
2035
+			if ($otherObject->ID()) {
2036
+				//its saved so assumed relations exist in the DB, so we can just
2037
+				//clear the cache so future queries use the updated info in the DB
2038
+				$otherObject->clear_cache($model->get_this_model_name(), null, true);
2039
+			} else {
2040
+				//it's not saved, so it caches relations like this
2041
+				$otherObject->cache($model->get_this_model_name(), $this);
2042
+			}
2043
+		}
2044
+		return $otherObject;
2045
+	}
2046
+
2047
+
2048
+
2049
+	/**
2050
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2051
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2052
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2053
+	 * from the cache
2054
+	 *
2055
+	 * @param mixed  $otherObjectModelObjectOrID
2056
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2057
+	 *                to the DB yet
2058
+	 * @param string $relationName
2059
+	 * @param array  $where_query
2060
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2061
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2062
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2063
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2064
+	 *                created in the join table.
2065
+	 * @return EE_Base_Class the relation was removed from
2066
+	 * @throws \EE_Error
2067
+	 */
2068
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2069
+	{
2070
+		if ($this->ID()) {
2071
+			//if this exists in the DB, save the relation change to the DB too
2072
+			$otherObject = $this->get_model()
2073
+								->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2074
+									$where_query);
2075
+			$this->clear_cache($relationName, $otherObject);
2076
+		} else {
2077
+			//this doesn't exist in the DB, just remove it from the cache
2078
+			$otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2079
+		}
2080
+		if ($otherObject instanceof EE_Base_Class) {
2081
+			$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2082
+		}
2083
+		return $otherObject;
2084
+	}
2085
+
2086
+
2087
+
2088
+	/**
2089
+	 * Removes ALL the related things for the $relationName.
2090
+	 *
2091
+	 * @param string $relationName
2092
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2093
+	 * @return EE_Base_Class
2094
+	 * @throws \EE_Error
2095
+	 */
2096
+	public function _remove_relations($relationName, $where_query_params = array())
2097
+	{
2098
+		if ($this->ID()) {
2099
+			//if this exists in the DB, save the relation change to the DB too
2100
+			$otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2101
+			$this->clear_cache($relationName, null, true);
2102
+		} else {
2103
+			//this doesn't exist in the DB, just remove it from the cache
2104
+			$otherObjects = $this->clear_cache($relationName, null, true);
2105
+		}
2106
+		if (is_array($otherObjects)) {
2107
+			foreach ($otherObjects as $otherObject) {
2108
+				$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2109
+			}
2110
+		}
2111
+		return $otherObjects;
2112
+	}
2113
+
2114
+
2115
+
2116
+	/**
2117
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2118
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2119
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2120
+	 * because we want to get even deleted items etc.
2121
+	 *
2122
+	 * @param string $relationName key in the model's _model_relations array
2123
+	 * @param array  $query_params like EEM_Base::get_all
2124
+	 * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2125
+	 * @throws \EE_Error
2126
+	 *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2127
+	 *                             you want IDs
2128
+	 */
2129
+	public function get_many_related($relationName, $query_params = array())
2130
+	{
2131
+		if ($this->ID()) {
2132
+			//this exists in the DB, so get the related things from either the cache or the DB
2133
+			//if there are query parameters, forget about caching the related model objects.
2134
+			if ($query_params) {
2135
+				$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2136
+			} else {
2137
+				//did we already cache the result of this query?
2138
+				$cached_results = $this->get_all_from_cache($relationName);
2139
+				if ( ! $cached_results) {
2140
+					$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2141
+					//if no query parameters were passed, then we got all the related model objects
2142
+					//for that relation. We can cache them then.
2143
+					foreach ($related_model_objects as $related_model_object) {
2144
+						$this->cache($relationName, $related_model_object);
2145
+					}
2146
+				} else {
2147
+					$related_model_objects = $cached_results;
2148
+				}
2149
+			}
2150
+		} else {
2151
+			//this doesn't exist in the DB, so just get the related things from the cache
2152
+			$related_model_objects = $this->get_all_from_cache($relationName);
2153
+		}
2154
+		return $related_model_objects;
2155
+	}
2156
+
2157
+
2158
+
2159
+	/**
2160
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2161
+	 * unless otherwise specified in the $query_params
2162
+	 *
2163
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2164
+	 * @param array  $query_params   like EEM_Base::get_all's
2165
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2166
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2167
+	 *                               that by the setting $distinct to TRUE;
2168
+	 * @return int
2169
+	 */
2170
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2171
+	{
2172
+		return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2173
+	}
2174
+
2175
+
2176
+
2177
+	/**
2178
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2179
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2180
+	 *
2181
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2182
+	 * @param array  $query_params  like EEM_Base::get_all's
2183
+	 * @param string $field_to_sum  name of field to count by.
2184
+	 *                              By default, uses primary key (which doesn't make much sense, so you should probably
2185
+	 *                              change it)
2186
+	 * @return int
2187
+	 */
2188
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2189
+	{
2190
+		return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2191
+	}
2192
+
2193
+
2194
+
2195
+	/**
2196
+	 * Gets the first (ie, one) related model object of the specified type.
2197
+	 *
2198
+	 * @param string $relationName key in the model's _model_relations array
2199
+	 * @param array  $query_params like EEM_Base::get_all
2200
+	 * @return EE_Base_Class (not an array, a single object)
2201
+	 * @throws \EE_Error
2202
+	 */
2203
+	public function get_first_related($relationName, $query_params = array())
2204
+	{
2205
+		$model = $this->get_model();
2206
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2207
+			//if they've provided some query parameters, don't bother trying to cache the result
2208
+			//also make sure we're not caching the result of get_first_related
2209
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2210
+			if ($query_params
2211
+				|| ! $model->related_settings_for($relationName)
2212
+					 instanceof
2213
+					 EE_Belongs_To_Relation
2214
+			) {
2215
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2216
+			} else {
2217
+				//first, check if we've already cached the result of this query
2218
+				$cached_result = $this->get_one_from_cache($relationName);
2219
+				if ( ! $cached_result) {
2220
+					$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2221
+					$this->cache($relationName, $related_model_object);
2222
+				} else {
2223
+					$related_model_object = $cached_result;
2224
+				}
2225
+			}
2226
+		} else {
2227
+			$related_model_object = null;
2228
+			//this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2229
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2230
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2231
+			}
2232
+			//this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2233
+			if ( ! $related_model_object) {
2234
+				$related_model_object = $this->get_one_from_cache($relationName);
2235
+			}
2236
+		}
2237
+		return $related_model_object;
2238
+	}
2239
+
2240
+
2241
+
2242
+	/**
2243
+	 * Does a delete on all related objects of type $relationName and removes
2244
+	 * the current model object's relation to them. If they can't be deleted (because
2245
+	 * of blocking related model objects) does nothing. If the related model objects are
2246
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2247
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2248
+	 *
2249
+	 * @param string $relationName
2250
+	 * @param array  $query_params like EEM_Base::get_all's
2251
+	 * @return int how many deleted
2252
+	 * @throws \EE_Error
2253
+	 */
2254
+	public function delete_related($relationName, $query_params = array())
2255
+	{
2256
+		if ($this->ID()) {
2257
+			$count = $this->get_model()->delete_related($this, $relationName, $query_params);
2258
+		} else {
2259
+			$count = count($this->get_all_from_cache($relationName));
2260
+			$this->clear_cache($relationName, null, true);
2261
+		}
2262
+		return $count;
2263
+	}
2264
+
2265
+
2266
+
2267
+	/**
2268
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2269
+	 * the current model object's relation to them. If they can't be deleted (because
2270
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2271
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2272
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2273
+	 *
2274
+	 * @param string $relationName
2275
+	 * @param array  $query_params like EEM_Base::get_all's
2276
+	 * @return int how many deleted (including those soft deleted)
2277
+	 * @throws \EE_Error
2278
+	 */
2279
+	public function delete_related_permanently($relationName, $query_params = array())
2280
+	{
2281
+		if ($this->ID()) {
2282
+			$count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2283
+		} else {
2284
+			$count = count($this->get_all_from_cache($relationName));
2285
+		}
2286
+		$this->clear_cache($relationName, null, true);
2287
+		return $count;
2288
+	}
2289
+
2290
+
2291
+
2292
+	/**
2293
+	 * is_set
2294
+	 * Just a simple utility function children can use for checking if property exists
2295
+	 *
2296
+	 * @access  public
2297
+	 * @param  string $field_name property to check
2298
+	 * @return bool                              TRUE if existing,FALSE if not.
2299
+	 */
2300
+	public function is_set($field_name)
2301
+	{
2302
+		return isset($this->_fields[$field_name]);
2303
+	}
2304
+
2305
+
2306
+
2307
+	/**
2308
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2309
+	 * EE_Error exception if they don't
2310
+	 *
2311
+	 * @param  mixed (string|array) $properties properties to check
2312
+	 * @throws EE_Error
2313
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2314
+	 */
2315
+	protected function _property_exists($properties)
2316
+	{
2317
+		foreach ((array)$properties as $property_name) {
2318
+			//first make sure this property exists
2319
+			if ( ! $this->_fields[$property_name]) {
2320
+				throw new EE_Error(
2321
+					sprintf(
2322
+						__(
2323
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2324
+							'event_espresso'
2325
+						),
2326
+						$property_name
2327
+					)
2328
+				);
2329
+			}
2330
+		}
2331
+		return true;
2332
+	}
2333
+
2334
+
2335
+
2336
+	/**
2337
+	 * This simply returns an array of model fields for this object
2338
+	 *
2339
+	 * @return array
2340
+	 * @throws \EE_Error
2341
+	 */
2342
+	public function model_field_array()
2343
+	{
2344
+		$fields = $this->get_model()->field_settings(false);
2345
+		$properties = array();
2346
+		//remove prepended underscore
2347
+		foreach ($fields as $field_name => $settings) {
2348
+			$properties[$field_name] = $this->get($field_name);
2349
+		}
2350
+		return $properties;
2351
+	}
2352
+
2353
+
2354
+
2355
+	/**
2356
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2357
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2358
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2359
+	 * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2360
+	 * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2361
+	 * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2362
+	 * was called, and an array of the original arguments passed to the function. Whatever their callback function
2363
+	 * returns will be returned by this function. Example: in functions.php (or in a plugin):
2364
+	 * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2365
+	 * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2366
+	 * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2367
+	 *        return $previousReturnValue.$returnString;
2368
+	 * }
2369
+	 * require('EE_Answer.class.php');
2370
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2371
+	 * echo $answer->my_callback('monkeys',100);
2372
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2373
+	 *
2374
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2375
+	 * @param array  $args       array of original arguments passed to the function
2376
+	 * @throws EE_Error
2377
+	 * @return mixed whatever the plugin which calls add_filter decides
2378
+	 */
2379
+	public function __call($methodName, $args)
2380
+	{
2381
+		$className = get_class($this);
2382
+		$tagName = "FHEE__{$className}__{$methodName}";
2383
+		if ( ! has_filter($tagName)) {
2384
+			throw new EE_Error(
2385
+				sprintf(
2386
+					__(
2387
+						"Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2388
+						"event_espresso"
2389
+					),
2390
+					$methodName,
2391
+					$className,
2392
+					$tagName
2393
+				)
2394
+			);
2395
+		}
2396
+		return apply_filters($tagName, null, $this, $args);
2397
+	}
2398
+
2399
+
2400
+
2401
+	/**
2402
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2403
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2404
+	 *
2405
+	 * @param string $meta_key
2406
+	 * @param mixed  $meta_value
2407
+	 * @param mixed  $previous_value
2408
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2409
+	 * @throws \EE_Error
2410
+	 * NOTE: if the values haven't changed, returns 0
2411
+	 */
2412
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2413
+	{
2414
+		$query_params = array(
2415
+			array(
2416
+				'EXM_key'  => $meta_key,
2417
+				'OBJ_ID'   => $this->ID(),
2418
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2419
+			),
2420
+		);
2421
+		if ($previous_value !== null) {
2422
+			$query_params[0]['EXM_value'] = $meta_value;
2423
+		}
2424
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2425
+		if ( ! $existing_rows_like_that) {
2426
+			return $this->add_extra_meta($meta_key, $meta_value);
2427
+		}
2428
+		foreach ($existing_rows_like_that as $existing_row) {
2429
+			$existing_row->save(array('EXM_value' => $meta_value));
2430
+		}
2431
+		return count($existing_rows_like_that);
2432
+	}
2433
+
2434
+
2435
+
2436
+	/**
2437
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2438
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2439
+	 * extra meta row was entered, false if not
2440
+	 *
2441
+	 * @param string  $meta_key
2442
+	 * @param mixed   $meta_value
2443
+	 * @param boolean $unique
2444
+	 * @return boolean
2445
+	 * @throws \EE_Error
2446
+	 */
2447
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2448
+	{
2449
+		if ($unique) {
2450
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2451
+				array(
2452
+					array(
2453
+						'EXM_key'  => $meta_key,
2454
+						'OBJ_ID'   => $this->ID(),
2455
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2456
+					),
2457
+				)
2458
+			);
2459
+			if ($existing_extra_meta) {
2460
+				return false;
2461
+			}
2462
+		}
2463
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2464
+			array(
2465
+				'EXM_key'   => $meta_key,
2466
+				'EXM_value' => $meta_value,
2467
+				'OBJ_ID'    => $this->ID(),
2468
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2469
+			)
2470
+		);
2471
+		$new_extra_meta->save();
2472
+		return true;
2473
+	}
2474
+
2475
+
2476
+
2477
+	/**
2478
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2479
+	 * is specified, only deletes extra meta records with that value.
2480
+	 *
2481
+	 * @param string $meta_key
2482
+	 * @param mixed  $meta_value
2483
+	 * @return int number of extra meta rows deleted
2484
+	 * @throws \EE_Error
2485
+	 */
2486
+	public function delete_extra_meta($meta_key, $meta_value = null)
2487
+	{
2488
+		$query_params = array(
2489
+			array(
2490
+				'EXM_key'  => $meta_key,
2491
+				'OBJ_ID'   => $this->ID(),
2492
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2493
+			),
2494
+		);
2495
+		if ($meta_value !== null) {
2496
+			$query_params[0]['EXM_value'] = $meta_value;
2497
+		}
2498
+		return EEM_Extra_Meta::instance()->delete($query_params);
2499
+	}
2500
+
2501
+
2502
+
2503
+	/**
2504
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2505
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2506
+	 * You can specify $default is case you haven't found the extra meta
2507
+	 *
2508
+	 * @param string  $meta_key
2509
+	 * @param boolean $single
2510
+	 * @param mixed   $default if we don't find anything, what should we return?
2511
+	 * @return mixed single value if $single; array if ! $single
2512
+	 * @throws \EE_Error
2513
+	 */
2514
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2515
+	{
2516
+		if ($single) {
2517
+			$result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2518
+			if ($result instanceof EE_Extra_Meta) {
2519
+				return $result->value();
2520
+			} else {
2521
+				return $default;
2522
+			}
2523
+		} else {
2524
+			$results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2525
+			if ($results) {
2526
+				$values = array();
2527
+				foreach ($results as $result) {
2528
+					if ($result instanceof EE_Extra_Meta) {
2529
+						$values[$result->ID()] = $result->value();
2530
+					}
2531
+				}
2532
+				return $values;
2533
+			} else {
2534
+				return $default;
2535
+			}
2536
+		}
2537
+	}
2538
+
2539
+
2540
+
2541
+	/**
2542
+	 * Returns a simple array of all the extra meta associated with this model object.
2543
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2544
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2545
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2546
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2547
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2548
+	 * finally the extra meta's value as each sub-value. (eg
2549
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2550
+	 *
2551
+	 * @param boolean $one_of_each_key
2552
+	 * @return array
2553
+	 * @throws \EE_Error
2554
+	 */
2555
+	public function all_extra_meta_array($one_of_each_key = true)
2556
+	{
2557
+		$return_array = array();
2558
+		if ($one_of_each_key) {
2559
+			$extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2560
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2561
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2562
+					$return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2563
+				}
2564
+			}
2565
+		} else {
2566
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2567
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2568
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2569
+					if ( ! isset($return_array[$extra_meta_obj->key()])) {
2570
+						$return_array[$extra_meta_obj->key()] = array();
2571
+					}
2572
+					$return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2573
+				}
2574
+			}
2575
+		}
2576
+		return $return_array;
2577
+	}
2578
+
2579
+
2580
+
2581
+	/**
2582
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2583
+	 *
2584
+	 * @return string
2585
+	 * @throws \EE_Error
2586
+	 */
2587
+	public function name()
2588
+	{
2589
+		//find a field that's not a text field
2590
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2591
+		if ($field_we_can_use) {
2592
+			return $this->get($field_we_can_use->get_name());
2593
+		} else {
2594
+			$first_few_properties = $this->model_field_array();
2595
+			$first_few_properties = array_slice($first_few_properties, 0, 3);
2596
+			$name_parts = array();
2597
+			foreach ($first_few_properties as $name => $value) {
2598
+				$name_parts[] = "$name:$value";
2599
+			}
2600
+			return implode(",", $name_parts);
2601
+		}
2602
+	}
2603
+
2604
+
2605
+
2606
+	/**
2607
+	 * in_entity_map
2608
+	 * Checks if this model object has been proven to already be in the entity map
2609
+	 *
2610
+	 * @return boolean
2611
+	 * @throws \EE_Error
2612
+	 */
2613
+	public function in_entity_map()
2614
+	{
2615
+		if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2616
+			//well, if we looked, did we find it in the entity map?
2617
+			return true;
2618
+		} else {
2619
+			return false;
2620
+		}
2621
+	}
2622
+
2623
+
2624
+
2625
+	/**
2626
+	 * refresh_from_db
2627
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
2628
+	 *
2629
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2630
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2631
+	 */
2632
+	public function refresh_from_db()
2633
+	{
2634
+		if ($this->ID() && $this->in_entity_map()) {
2635
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
2636
+		} else {
2637
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2638
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
2639
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2640
+			//absolutely nothing in it for this ID
2641
+			if (WP_DEBUG) {
2642
+				throw new EE_Error(
2643
+					sprintf(
2644
+						__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2645
+							'event_espresso'),
2646
+						$this->ID(),
2647
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2648
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2649
+					)
2650
+				);
2651
+			}
2652
+		}
2653
+	}
2654
+
2655
+
2656
+
2657
+	/**
2658
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2659
+	 * (probably a bad assumption they have made, oh well)
2660
+	 *
2661
+	 * @return string
2662
+	 */
2663
+	public function __toString()
2664
+	{
2665
+		try {
2666
+			return sprintf('%s (%s)', $this->name(), $this->ID());
2667
+		} catch (Exception $e) {
2668
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2669
+			return '';
2670
+		}
2671
+	}
2672
+
2673
+
2674
+
2675
+	/**
2676
+	 * Clear related model objects if they're already in the DB, because otherwise when we
2677
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
2678
+	 * This means if we have made changes to those related model objects, and want to unserialize
2679
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
2680
+	 * Instead, those related model objects should be directly serialized and stored.
2681
+	 * Eg, the following won't work:
2682
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2683
+	 * $att = $reg->attendee();
2684
+	 * $att->set( 'ATT_fname', 'Dirk' );
2685
+	 * update_option( 'my_option', serialize( $reg ) );
2686
+	 * //END REQUEST
2687
+	 * //START NEXT REQUEST
2688
+	 * $reg = get_option( 'my_option' );
2689
+	 * $reg->attendee()->save();
2690
+	 * And would need to be replace with:
2691
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2692
+	 * $att = $reg->attendee();
2693
+	 * $att->set( 'ATT_fname', 'Dirk' );
2694
+	 * update_option( 'my_option', serialize( $reg ) );
2695
+	 * //END REQUEST
2696
+	 * //START NEXT REQUEST
2697
+	 * $att = get_option( 'my_option' );
2698
+	 * $att->save();
2699
+	 *
2700
+	 * @return array
2701
+	 * @throws \EE_Error
2702
+	 */
2703
+	public function __sleep()
2704
+	{
2705
+		$model = $this->get_model();
2706
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2707
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
2708
+				$classname = 'EE_' . $model->get_this_model_name();
2709
+				if (
2710
+					$this->get_one_from_cache($relation_name) instanceof $classname
2711
+					&& $this->get_one_from_cache($relation_name)->ID()
2712
+				) {
2713
+					$this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2714
+				}
2715
+			}
2716
+		}
2717
+		$this->_props_n_values_provided_in_constructor = array();
2718
+		$properties_to_serialize = get_object_vars($this);
2719
+		//don't serialize the model. It's big and that risks recursion
2720
+		unset($properties_to_serialize['_model']);
2721
+		return array_keys($properties_to_serialize);
2722
+	}
2723
+
2724
+
2725
+
2726
+	/**
2727
+	 * restore _props_n_values_provided_in_constructor
2728
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2729
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
2730
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
2731
+	 */
2732
+	public function __wakeup()
2733
+	{
2734
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
2735
+	}
2736 2736
 
2737 2737
 
2738 2738
 
Please login to merge, or discard this patch.
core/EE_Module_Request_Router.core.php 2 patches
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
         // assume this if first route being called
56 56
         $previous_route = false;
57 57
         // but is it really ???
58
-        if (! empty(self::$_previous_routes)) {
58
+        if ( ! empty(self::$_previous_routes)) {
59 59
             // get last run route
60 60
             $previous_routes = array_values(self::$_previous_routes);
61 61
             $previous_route = array_pop($previous_routes);
@@ -135,36 +135,36 @@  discard block
 block discarded – undo
135 135
             return false;
136 136
         }
137 137
         // verify that result is an array
138
-        if (! is_array($module_method)) {
138
+        if ( ! is_array($module_method)) {
139 139
             $msg = sprintf(__('The %s  route has not been properly registered.', 'event_espresso'), $current_route);
140
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
140
+            EE_Error::add_error($msg.'||'.$msg, __FILE__, __FUNCTION__, __LINE__);
141 141
             return false;
142 142
         }
143 143
         // grab module name
144 144
         $module_name = $module_method[0];
145 145
         // verify that a class method was registered properly
146
-        if (! isset($module_method[1])) {
146
+        if ( ! isset($module_method[1])) {
147 147
             $msg = sprintf(
148 148
                 __('A class method for the %s  route has not been properly registered.', 'event_espresso'),
149 149
                 $current_route
150 150
             );
151
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
151
+            EE_Error::add_error($msg.'||'.$msg, __FILE__, __FUNCTION__, __LINE__);
152 152
             return false;
153 153
         }
154 154
         // grab method
155 155
         $method = $module_method[1];
156 156
         // verify that class exists
157
-        if (! class_exists($module_name)) {
157
+        if ( ! class_exists($module_name)) {
158 158
             $msg = sprintf(__('The requested %s class could not be found.', 'event_espresso'), $module_name);
159 159
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
160 160
             return false;
161 161
         }
162 162
         // verify that method exists
163
-        if (! method_exists($module_name, $method)) {
163
+        if ( ! method_exists($module_name, $method)) {
164 164
             $msg = sprintf(
165 165
                 __('The class method %s for the %s route is in invalid.', 'event_espresso'), $method, $current_route
166 166
             );
167
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
167
+            EE_Error::add_error($msg.'||'.$msg, __FILE__, __FUNCTION__, __LINE__);
168 168
             return false;
169 169
         }
170 170
         // instantiate module and call route method
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
         // instantiate module class
197 197
         $module = new $module_name();
198 198
         // ensure that class is actually a module
199
-        if (! $module instanceof EED_Module) {
199
+        if ( ! $module instanceof EED_Module) {
200 200
             EE_Error::add_error(
201 201
                 sprintf(__('The requested %s module is not of the class EED_Module.', 'event_espresso'), $module_name),
202 202
                 __FILE__, __FUNCTION__, __LINE__
Please login to merge, or discard this patch.
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -17,248 +17,248 @@
 block discarded – undo
17 17
 final class EE_Module_Request_Router implements InterminableInterface
18 18
 {
19 19
 
20
-    /**
21
-     * @var EE_Request $request
22
-     */
23
-    private $request;
20
+	/**
21
+	 * @var EE_Request $request
22
+	 */
23
+	private $request;
24 24
 
25
-    /**
26
-     * @var array $_previous_routes
27
-     */
28
-    private static $_previous_routes = array();
25
+	/**
26
+	 * @var array $_previous_routes
27
+	 */
28
+	private static $_previous_routes = array();
29 29
 
30
-    /**
31
-     * @var WP_Query $WP_Query
32
-     */
33
-    public $WP_Query;
30
+	/**
31
+	 * @var WP_Query $WP_Query
32
+	 */
33
+	public $WP_Query;
34 34
 
35 35
 
36 36
 
37
-    /**
38
-     * EE_Module_Request_Router constructor.
39
-     *
40
-     * @param EE_Request $request
41
-     */
42
-    public function __construct(EE_Request $request)
43
-    {
44
-        $this->request = $request;
45
-    }
37
+	/**
38
+	 * EE_Module_Request_Router constructor.
39
+	 *
40
+	 * @param EE_Request $request
41
+	 */
42
+	public function __construct(EE_Request $request)
43
+	{
44
+		$this->request = $request;
45
+	}
46 46
 
47 47
 
48 48
 
49
-    /**
50
-     * on the first call  to this method, it checks the EE_Request_Handler for a "route"
51
-     * on subsequent calls to this method,
52
-     * instead of checking the EE_Request_Handler for a route, it checks the previous routes array,
53
-     * and checks if the last called route has any forwarding routes registered for it
54
-     *
55
-     * @param WP_Query $WP_Query
56
-     * @return NULL|string
57
-     * @throws EE_Error
58
-     * @throws ReflectionException
59
-     */
60
-    public function get_route(WP_Query $WP_Query)
61
-    {
62
-        $this->WP_Query = $WP_Query;
63
-        // assume this if first route being called
64
-        $previous_route = false;
65
-        // but is it really ???
66
-        if (! empty(self::$_previous_routes)) {
67
-            // get last run route
68
-            $previous_routes = array_values(self::$_previous_routes);
69
-            $previous_route = array_pop($previous_routes);
70
-        }
71
-        //  has another route already been run ?
72
-        if ($previous_route) {
73
-            // check if  forwarding has been set
74
-            $current_route = $this->get_forward($previous_route);
75
-            try {
76
-                //check for recursive forwarding
77
-                if (isset(self::$_previous_routes[$current_route])) {
78
-                    throw new EE_Error(
79
-                        sprintf(
80
-                            __(
81
-                                'An error occurred. The %s route has already been called, and therefore can not be forwarded to, because an infinite loop would be created and break the interweb.',
82
-                                'event_espresso'
83
-                            ),
84
-                            $current_route
85
-                        )
86
-                    );
87
-                }
88
-            } catch (EE_Error $e) {
89
-                $e->get_error();
90
-                return null;
91
-            }
92
-        } else {
93
-            // first route called
94
-            $current_route = null;
95
-            // grab all routes
96
-            $routes = EE_Config::get_routes();
97
-            //d( $routes );
98
-            foreach ($routes as $key => $route) {
99
-                // check request for module route
100
-                if ($this->request->is_set($key)) {
101
-                    $current_route = sanitize_text_field($this->request->get($key));
102
-                    if ($current_route) {
103
-                        $current_route = array($key, $current_route);
104
-                        break;
105
-                    }
106
-                }
107
-            }
108
-        }
109
-        // sorry, but I can't read what you route !
110
-        if (empty($current_route)) {
111
-            return null;
112
-        }
113
-        //add route to previous routes array
114
-        self::$_previous_routes[] = $current_route;
115
-        return $current_route;
116
-    }
49
+	/**
50
+	 * on the first call  to this method, it checks the EE_Request_Handler for a "route"
51
+	 * on subsequent calls to this method,
52
+	 * instead of checking the EE_Request_Handler for a route, it checks the previous routes array,
53
+	 * and checks if the last called route has any forwarding routes registered for it
54
+	 *
55
+	 * @param WP_Query $WP_Query
56
+	 * @return NULL|string
57
+	 * @throws EE_Error
58
+	 * @throws ReflectionException
59
+	 */
60
+	public function get_route(WP_Query $WP_Query)
61
+	{
62
+		$this->WP_Query = $WP_Query;
63
+		// assume this if first route being called
64
+		$previous_route = false;
65
+		// but is it really ???
66
+		if (! empty(self::$_previous_routes)) {
67
+			// get last run route
68
+			$previous_routes = array_values(self::$_previous_routes);
69
+			$previous_route = array_pop($previous_routes);
70
+		}
71
+		//  has another route already been run ?
72
+		if ($previous_route) {
73
+			// check if  forwarding has been set
74
+			$current_route = $this->get_forward($previous_route);
75
+			try {
76
+				//check for recursive forwarding
77
+				if (isset(self::$_previous_routes[$current_route])) {
78
+					throw new EE_Error(
79
+						sprintf(
80
+							__(
81
+								'An error occurred. The %s route has already been called, and therefore can not be forwarded to, because an infinite loop would be created and break the interweb.',
82
+								'event_espresso'
83
+							),
84
+							$current_route
85
+						)
86
+					);
87
+				}
88
+			} catch (EE_Error $e) {
89
+				$e->get_error();
90
+				return null;
91
+			}
92
+		} else {
93
+			// first route called
94
+			$current_route = null;
95
+			// grab all routes
96
+			$routes = EE_Config::get_routes();
97
+			//d( $routes );
98
+			foreach ($routes as $key => $route) {
99
+				// check request for module route
100
+				if ($this->request->is_set($key)) {
101
+					$current_route = sanitize_text_field($this->request->get($key));
102
+					if ($current_route) {
103
+						$current_route = array($key, $current_route);
104
+						break;
105
+					}
106
+				}
107
+			}
108
+		}
109
+		// sorry, but I can't read what you route !
110
+		if (empty($current_route)) {
111
+			return null;
112
+		}
113
+		//add route to previous routes array
114
+		self::$_previous_routes[] = $current_route;
115
+		return $current_route;
116
+	}
117 117
 
118 118
 
119 119
 
120
-    /**
121
-     * this method simply takes a valid route, and resolves what module class method the route points to
122
-     *
123
-     * @param string $key
124
-     * @param string $current_route
125
-     * @return mixed EED_Module | boolean
126
-     * @throws EE_Error
127
-     * @throws ReflectionException
128
-     */
129
-    public function resolve_route($key, $current_route)
130
-    {
131
-        // get module method that route has been mapped to
132
-        $module_method = EE_Config::get_route($current_route, $key);
133
-        // verify result was returned
134
-        if (empty($module_method)) {
135
-            $msg = sprintf(
136
-                __('The requested route %s could not be mapped to any registered modules.', 'event_espresso'),
137
-                $current_route
138
-            );
139
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
140
-            return false;
141
-        }
142
-        // verify that result is an array
143
-        if (! is_array($module_method)) {
144
-            $msg = sprintf(__('The %s  route has not been properly registered.', 'event_espresso'), $current_route);
145
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
146
-            return false;
147
-        }
148
-        // grab module name
149
-        $module_name = $module_method[0];
150
-        // verify that a class method was registered properly
151
-        if (! isset($module_method[1])) {
152
-            $msg = sprintf(
153
-                __('A class method for the %s  route has not been properly registered.', 'event_espresso'),
154
-                $current_route
155
-            );
156
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
157
-            return false;
158
-        }
159
-        // grab method
160
-        $method = $module_method[1];
161
-        // verify that class exists
162
-        if (! class_exists($module_name)) {
163
-            $msg = sprintf(__('The requested %s class could not be found.', 'event_espresso'), $module_name);
164
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
165
-            return false;
166
-        }
167
-        // verify that method exists
168
-        if (! method_exists($module_name, $method)) {
169
-            $msg = sprintf(
170
-                __('The class method %s for the %s route is in invalid.', 'event_espresso'), $method, $current_route
171
-            );
172
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
173
-            return false;
174
-        }
175
-        // instantiate module and call route method
176
-        return $this->_module_router($module_name, $method);
177
-    }
120
+	/**
121
+	 * this method simply takes a valid route, and resolves what module class method the route points to
122
+	 *
123
+	 * @param string $key
124
+	 * @param string $current_route
125
+	 * @return mixed EED_Module | boolean
126
+	 * @throws EE_Error
127
+	 * @throws ReflectionException
128
+	 */
129
+	public function resolve_route($key, $current_route)
130
+	{
131
+		// get module method that route has been mapped to
132
+		$module_method = EE_Config::get_route($current_route, $key);
133
+		// verify result was returned
134
+		if (empty($module_method)) {
135
+			$msg = sprintf(
136
+				__('The requested route %s could not be mapped to any registered modules.', 'event_espresso'),
137
+				$current_route
138
+			);
139
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
140
+			return false;
141
+		}
142
+		// verify that result is an array
143
+		if (! is_array($module_method)) {
144
+			$msg = sprintf(__('The %s  route has not been properly registered.', 'event_espresso'), $current_route);
145
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
146
+			return false;
147
+		}
148
+		// grab module name
149
+		$module_name = $module_method[0];
150
+		// verify that a class method was registered properly
151
+		if (! isset($module_method[1])) {
152
+			$msg = sprintf(
153
+				__('A class method for the %s  route has not been properly registered.', 'event_espresso'),
154
+				$current_route
155
+			);
156
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
157
+			return false;
158
+		}
159
+		// grab method
160
+		$method = $module_method[1];
161
+		// verify that class exists
162
+		if (! class_exists($module_name)) {
163
+			$msg = sprintf(__('The requested %s class could not be found.', 'event_espresso'), $module_name);
164
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
165
+			return false;
166
+		}
167
+		// verify that method exists
168
+		if (! method_exists($module_name, $method)) {
169
+			$msg = sprintf(
170
+				__('The class method %s for the %s route is in invalid.', 'event_espresso'), $method, $current_route
171
+			);
172
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
173
+			return false;
174
+		}
175
+		// instantiate module and call route method
176
+		return $this->_module_router($module_name, $method);
177
+	}
178 178
 
179 179
 
180 180
 
181
-    /**
182
-     * this method instantiates modules and calls the method that was defined when the route was registered
183
-     *
184
-     * @param string $module_name
185
-     * @return EED_Module|object|null
186
-     * @throws ReflectionException
187
-     */
188
-    public static function module_factory($module_name)
189
-    {
190
-        if ($module_name === 'EED_Module') {
191
-            EE_Error::add_error(
192
-                sprintf(
193
-                    __(
194
-                        'EED_Module is an abstract parent class an can not be instantiated. Please provide a proper module name.',
195
-                        'event_espresso'
196
-                    ), $module_name
197
-                ), __FILE__, __FUNCTION__, __LINE__
198
-            );
199
-            return null;
200
-        }
201
-        // instantiate module class
202
-        $module = new $module_name();
203
-        // ensure that class is actually a module
204
-        if (! $module instanceof EED_Module) {
205
-            EE_Error::add_error(
206
-                sprintf(__('The requested %s module is not of the class EED_Module.', 'event_espresso'), $module_name),
207
-                __FILE__, __FUNCTION__, __LINE__
208
-            );
209
-            return null;
210
-        }
211
-        return $module;
212
-    }
181
+	/**
182
+	 * this method instantiates modules and calls the method that was defined when the route was registered
183
+	 *
184
+	 * @param string $module_name
185
+	 * @return EED_Module|object|null
186
+	 * @throws ReflectionException
187
+	 */
188
+	public static function module_factory($module_name)
189
+	{
190
+		if ($module_name === 'EED_Module') {
191
+			EE_Error::add_error(
192
+				sprintf(
193
+					__(
194
+						'EED_Module is an abstract parent class an can not be instantiated. Please provide a proper module name.',
195
+						'event_espresso'
196
+					), $module_name
197
+				), __FILE__, __FUNCTION__, __LINE__
198
+			);
199
+			return null;
200
+		}
201
+		// instantiate module class
202
+		$module = new $module_name();
203
+		// ensure that class is actually a module
204
+		if (! $module instanceof EED_Module) {
205
+			EE_Error::add_error(
206
+				sprintf(__('The requested %s module is not of the class EED_Module.', 'event_espresso'), $module_name),
207
+				__FILE__, __FUNCTION__, __LINE__
208
+			);
209
+			return null;
210
+		}
211
+		return $module;
212
+	}
213 213
 
214 214
 
215 215
 
216
-    /**
217
-     * this method instantiates modules and calls the method that was defined when the route was registered
218
-     *
219
-     * @param string $module_name
220
-     * @param string $method
221
-     * @return EED_Module|null
222
-     * @throws EE_Error
223
-     * @throws ReflectionException
224
-     */
225
-    private function _module_router($module_name, $method)
226
-    {
227
-        // instantiate module class
228
-        $module = EE_Module_Request_Router::module_factory($module_name);
229
-        if ($module instanceof EED_Module) {
230
-            // and call whatever action the route was for
231
-            try {
232
-                call_user_func(array($module, $method), $this->WP_Query);
233
-            } catch (EE_Error $e) {
234
-                $e->get_error();
235
-                return null;
236
-            }
237
-        }
238
-        return $module;
239
-    }
216
+	/**
217
+	 * this method instantiates modules and calls the method that was defined when the route was registered
218
+	 *
219
+	 * @param string $module_name
220
+	 * @param string $method
221
+	 * @return EED_Module|null
222
+	 * @throws EE_Error
223
+	 * @throws ReflectionException
224
+	 */
225
+	private function _module_router($module_name, $method)
226
+	{
227
+		// instantiate module class
228
+		$module = EE_Module_Request_Router::module_factory($module_name);
229
+		if ($module instanceof EED_Module) {
230
+			// and call whatever action the route was for
231
+			try {
232
+				call_user_func(array($module, $method), $this->WP_Query);
233
+			} catch (EE_Error $e) {
234
+				$e->get_error();
235
+				return null;
236
+			}
237
+		}
238
+		return $module;
239
+	}
240 240
 
241 241
 
242 242
 
243
-    /**
244
-     * @param $current_route
245
-     * @return string
246
-     */
247
-    public function get_forward($current_route)
248
-    {
249
-        return EE_Config::get_forward($current_route);
250
-    }
243
+	/**
244
+	 * @param $current_route
245
+	 * @return string
246
+	 */
247
+	public function get_forward($current_route)
248
+	{
249
+		return EE_Config::get_forward($current_route);
250
+	}
251 251
 
252 252
 
253 253
 
254
-    /**
255
-     * @param $current_route
256
-     * @return string
257
-     */
258
-    public function get_view($current_route)
259
-    {
260
-        return EE_Config::get_view($current_route);
261
-    }
254
+	/**
255
+	 * @param $current_route
256
+	 * @return string
257
+	 */
258
+	public function get_view($current_route)
259
+	{
260
+		return EE_Config::get_view($current_route);
261
+	}
262 262
 
263 263
 
264 264
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_List_Table.class.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -152,7 +152,7 @@
 block discarded – undo
152 152
 
153 153
     /**
154 154
      * @param EE_Event $item
155
-     * @return mixed|string
155
+     * @return string
156 156
      * @throws EE_Error
157 157
      */
158 158
     public function column_id(EE_Event $item)
Please login to merge, or discard this patch.
Indentation   +508 added lines, -508 removed lines patch added patch discarded remove patch
@@ -13,512 +13,512 @@
 block discarded – undo
13 13
 class Events_Admin_List_Table extends EE_Admin_List_Table
14 14
 {
15 15
 
16
-    /**
17
-     * @var EE_Datetime
18
-     */
19
-    private $_dtt;
20
-
21
-
22
-    /**
23
-     * Initial setup of data properties for the list table.
24
-     */
25
-    protected function _setup_data()
26
-    {
27
-        $this->_data           = $this->_admin_page->get_events($this->_per_page, $this->_current_page);
28
-        $this->_all_data_count = $this->_admin_page->get_events(0, 0, true);
29
-    }
30
-
31
-
32
-    /**
33
-     * Set up of additional properties for the list table.
34
-     */
35
-    protected function _set_properties()
36
-    {
37
-        $this->_wp_list_args = array(
38
-            'singular' => esc_html__('event', 'event_espresso'),
39
-            'plural'   => esc_html__('events', 'event_espresso'),
40
-            'ajax'     => true, //for now
41
-            'screen'   => $this->_admin_page->get_current_screen()->id,
42
-        );
43
-
44
-
45
-        $this->_columns = array(
46
-            'cb'              => '<input type="checkbox" />',
47
-            'id'              => esc_html__('ID', 'event_espresso'),
48
-            'name'            => esc_html__('Name', 'event_espresso'),
49
-            'author'          => esc_html__('Author', 'event_espresso'),
50
-            'venue'           => esc_html__('Venue', 'event_espresso'),
51
-            'start_date_time' => esc_html__('Event Start', 'event_espresso'),
52
-            'reg_begins'      => esc_html__('On Sale', 'event_espresso'),
53
-            'attendees'       => '<span class="dashicons dashicons-groups ee-icon-color-ee-green ee-icon-size-20">'
54
-                                 . '</span>',
55
-            //'tkts_sold' => esc_html__('Tickets Sold', 'event_espresso'),
56
-            'actions'         => esc_html__('Actions', 'event_espresso'),
57
-        );
58
-
59
-
60
-        $this->_sortable_columns = array(
61
-            'id'              => array('EVT_ID' => true),
62
-            'name'            => array('EVT_name' => false),
63
-            'author'          => array('EVT_wp_user' => false),
64
-            'venue'           => array('Venue.VNU_name' => false),
65
-            'start_date_time' => array('Datetime.DTT_EVT_start' => false),
66
-            'reg_begins'      => array('Datetime.Ticket.TKT_start_date' => false),
67
-        );
68
-
69
-        $this->_primary_column = 'id';
70
-
71
-        $this->_hidden_columns = array('author');
72
-    }
73
-
74
-
75
-    /**
76
-     * @return array
77
-     */
78
-    protected function _get_table_filters()
79
-    {
80
-        return array(); //no filters with decaf
81
-    }
82
-
83
-
84
-    /**
85
-     * Setup of views properties.
86
-     */
87
-    protected function _add_view_counts()
88
-    {
89
-        $this->_views['all']['count']   = $this->_admin_page->total_events();
90
-        $this->_views['draft']['count'] = $this->_admin_page->total_events_draft();
91
-        if (EE_Registry::instance()->CAP->current_user_can(
92
-            'ee_delete_events',
93
-            'espresso_events_trash_events'
94
-        )) {
95
-            $this->_views['trash']['count'] = $this->_admin_page->total_trashed_events();
96
-        }
97
-    }
98
-
99
-
100
-    /**
101
-     * @param EE_Event $item
102
-     * @return string
103
-     * @throws EE_Error
104
-     */
105
-    protected function _get_row_class($item)
106
-    {
107
-        $class = parent::_get_row_class($item);
108
-        //add status class
109
-        $class .= $item instanceof EE_Event ? ' ee-status-strip event-status-' . $item->get_active_status() : '';
110
-        if ($this->_has_checkbox_column) {
111
-            $class .= ' has-checkbox-column';
112
-        }
113
-        return $class;
114
-    }
115
-
116
-
117
-    /**
118
-     * @param EE_Event $item
119
-     * @return string
120
-     * @throws EE_Error
121
-     */
122
-    public function column_status(EE_Event $item)
123
-    {
124
-        return '<span class="ee-status-strip ee-status-strip-td event-status-'
125
-               . $item->get_active_status()
126
-               . '"></span>';
127
-    }
128
-
129
-
130
-    /**
131
-     * @param  EE_Event $item
132
-     * @return string
133
-     * @throws EE_Error
134
-     */
135
-    public function column_cb($item)
136
-    {
137
-        if (! $item instanceof EE_Event) {
138
-            return '';
139
-        }
140
-        $this->_dtt = $item->primary_datetime(); //set this for use in other columns
141
-
142
-        //does event have any attached registrations?
143
-        $regs = $item->count_related('Registration');
144
-        return $regs > 0 && $this->_view == 'trash'
145
-            ? '<span class="ee-lock-icon"></span>'
146
-            : sprintf(
147
-                '<input type="checkbox" name="EVT_IDs[]" value="%s" />',
148
-                $item->ID()
149
-            );
150
-    }
151
-
152
-
153
-    /**
154
-     * @param EE_Event $item
155
-     * @return mixed|string
156
-     * @throws EE_Error
157
-     */
158
-    public function column_id(EE_Event $item)
159
-    {
160
-        $content = $item->ID();
161
-        $content .= '  <span class="show-on-mobile-view-only">' . $item->name() . '</span>';
162
-        return $content;
163
-    }
164
-
165
-
166
-    /**
167
-     * @param EE_Event $item
168
-     * @return string
169
-     * @throws EE_Error
170
-     */
171
-    public function column_name(EE_Event $item)
172
-    {
173
-        $edit_query_args = array(
174
-            'action' => 'edit',
175
-            'post'   => $item->ID(),
176
-        );
177
-        $edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
178
-        $actions         = $this->_column_name_action_setup($item);
179
-        $status          = ''; //$item->status() !== 'publish' ? ' (' . $item->status() . ')' : '';
180
-        $content         = '<strong><a class="row-title" href="'
181
-                           . $edit_link . '">'
182
-                           . $item->name()
183
-                           . '</a></strong>'
184
-                           . $status;
185
-        $content         .= '<br><span class="ee-status-text-small">'
186
-                            . EEH_Template::pretty_status(
187
-                                $item->get_active_status(),
188
-                                false,
189
-                                'sentence'
190
-                            )
191
-                            . '</span>';
192
-        $content         .= $this->row_actions($actions);
193
-        return $content;
194
-    }
195
-
196
-
197
-    /**
198
-     * Just a method for setting up the actions for the name column
199
-     *
200
-     * @param EE_Event $item
201
-     * @return array array of actions
202
-     * @throws EE_Error
203
-     */
204
-    protected function _column_name_action_setup(EE_Event $item)
205
-    {
206
-        //todo: remove when attendees is active
207
-        if (! defined('REG_ADMIN_URL')) {
208
-            define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
209
-        }
210
-
211
-        $actions = array();
212
-
213
-        if (EE_Registry::instance()->CAP->current_user_can(
214
-            'ee_edit_event',
215
-            'espresso_events_edit',
216
-            $item->ID()
217
-        )) {
218
-            $edit_query_args = array(
219
-                'action' => 'edit',
220
-                'post'   => $item->ID(),
221
-            );
222
-            $edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
223
-            $actions['edit'] = '<a href="' . $edit_link . '"'
224
-                               . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
225
-                               . esc_html__('Edit', 'event_espresso')
226
-                               . '</a>';
227
-
228
-        }
229
-
230
-        if (EE_Registry::instance()->CAP->current_user_can(
231
-            'ee_read_event',
232
-            'espresso_registrations_view_registration',
233
-            $item->ID()
234
-        )
235
-            && EE_Registry::instance()->CAP->current_user_can(
236
-                'ee_read_registrations',
237
-                'espresso_registrations_view_registration'
238
-            )
239
-        ) {
240
-            $attendees_query_args = array(
241
-                'action'   => 'default',
242
-                'event_id' => $item->ID(),
243
-            );
244
-            $attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
245
-            $actions['attendees'] = '<a href="' . $attendees_link . '"'
246
-                                    . ' title="' . esc_attr__('View Registrations', 'event_espresso') . '">'
247
-                                    . esc_html__('Registrations', 'event_espresso')
248
-                                    . '</a>';
249
-        }
250
-
251
-        if (EE_Registry::instance()->CAP->current_user_can(
252
-            'ee_delete_event',
253
-            'espresso_events_trash_event',
254
-            $item->ID()
255
-        )) {
256
-            $trash_event_query_args = array(
257
-                'action' => 'trash_event',
258
-                'EVT_ID' => $item->ID(),
259
-            );
260
-            $trash_event_link       = EE_Admin_Page::add_query_args_and_nonce(
261
-                $trash_event_query_args,
262
-                EVENTS_ADMIN_URL
263
-            );
264
-        }
265
-
266
-        if (EE_Registry::instance()->CAP->current_user_can(
267
-            'ee_delete_event',
268
-            'espresso_events_restore_event',
269
-            $item->ID()
270
-        )) {
271
-            $restore_event_query_args = array(
272
-                'action' => 'restore_event',
273
-                'EVT_ID' => $item->ID(),
274
-            );
275
-            $restore_event_link       = EE_Admin_Page::add_query_args_and_nonce(
276
-                $restore_event_query_args,
277
-                EVENTS_ADMIN_URL
278
-            );
279
-        }
280
-
281
-        if (EE_Registry::instance()->CAP->current_user_can(
282
-            'ee_delete_event',
283
-            'espresso_events_delete_event',
284
-            $item->ID()
285
-        )) {
286
-            $delete_event_query_args = array(
287
-                'action' => 'delete_event',
288
-                'EVT_ID' => $item->ID(),
289
-            );
290
-            $delete_event_link       = EE_Admin_Page::add_query_args_and_nonce(
291
-                $delete_event_query_args,
292
-                EVENTS_ADMIN_URL
293
-            );
294
-        }
295
-
296
-        $view_link = get_permalink($item->ID());
297
-
298
-        $actions['view'] = '<a href="' . $view_link . '"'
299
-                           . ' title="' . esc_attr__('View Event', 'event_espresso') . '">'
300
-                           . esc_html__('View', 'event_espresso')
301
-                           . '</a>';
302
-
303
-        switch ($item->get('status')) {
304
-            case 'trash':
305
-                if (EE_Registry::instance()->CAP->current_user_can(
306
-                    'ee_delete_event',
307
-                    'espresso_events_restore_event',
308
-                    $item->ID()
309
-                )) {
310
-                    $actions['restore_from_trash'] = '<a href="' . $restore_event_link . '"'
311
-                                                     . ' title="' . esc_attr__('Restore from Trash', 'event_espresso')
312
-                                                     . '">'
313
-                                                     . esc_html__('Restore from Trash', 'event_espresso')
314
-                                                     . '</a>';
315
-                }
316
-                if ($item->count_related('Registration') === 0
317
-                    && EE_Registry::instance()->CAP->current_user_can(
318
-                        'ee_delete_event',
319
-                        'espresso_events_delete_event',
320
-                        $item->ID()
321
-                    )) {
322
-                    $actions['delete'] = '<a href="' . $delete_event_link . '"'
323
-                                         . ' title="' . esc_attr__('Delete Permanently', 'event_espresso') . '">'
324
-                                         . esc_html__('Delete Permanently', 'event_espresso')
325
-                                         . '</a>';
326
-                }
327
-                break;
328
-            default:
329
-                if (EE_Registry::instance()->CAP->current_user_can(
330
-                    'ee_delete_event',
331
-                    'espresso_events_trash_event',
332
-                    $item->ID()
333
-                )) {
334
-                    $actions['move to trash'] = '<a href="' . $trash_event_link . '"'
335
-                                                . ' title="' . esc_attr__('Trash Event', 'event_espresso') . '">'
336
-                                                . esc_html__('Trash', 'event_espresso')
337
-                                                . '</a>';
338
-                }
339
-        }
340
-        return $actions;
341
-    }
342
-
343
-
344
-    /**
345
-     * @param EE_Event $item
346
-     * @return string
347
-     * @throws EE_Error
348
-     */
349
-    public function column_author(EE_Event $item)
350
-    {
351
-        //user author info
352
-        $event_author = get_userdata($item->wp_user());
353
-        $gravatar     = get_avatar($item->wp_user(), '15');
354
-        //filter link
355
-        $query_args = array(
356
-            'action'      => 'default',
357
-            'EVT_wp_user' => $item->wp_user(),
358
-        );
359
-        $filter_url = EE_Admin_Page::add_query_args_and_nonce($query_args, EVENTS_ADMIN_URL);
360
-        return $gravatar . '  <a href="' . $filter_url . '"'
361
-               . ' title="' . esc_attr__('Click to filter events by this author.', 'event_espresso') . '">'
362
-               . $event_author->display_name
363
-               . '</a>';
364
-    }
365
-
366
-
367
-    /**
368
-     * @param EE_Event $item
369
-     * @return string
370
-     * @throws EE_Error
371
-     */
372
-    public function column_venue(EE_Event $item)
373
-    {
374
-        $venue = $item->get_first_related('Venue');
375
-        return ! empty($venue) ? $venue->name() : '';
376
-    }
377
-
378
-
379
-    /**
380
-     * @param EE_Event $item
381
-     * @throws EE_Error
382
-     */
383
-    public function column_start_date_time(EE_Event $item)
384
-    {
385
-        echo ! empty($this->_dtt)
386
-            ? $this->_dtt->get_i18n_datetime('DTT_EVT_start')
387
-            : esc_html__('No Date was saved for this Event', 'event_espresso');
388
-        //display in user's timezone?
389
-        echo ! empty($this->_dtt)
390
-            ? $this->_dtt->display_in_my_timezone(
391
-                'DTT_EVT_start',
392
-                'get_i18n_datetime',
393
-                '',
394
-                'My Timezone: '
395
-            )
396
-            : '';
397
-    }
398
-
399
-
400
-    /**
401
-     * @param EE_Event $item
402
-     * @throws EE_Error
403
-     */
404
-    public function column_reg_begins(EE_Event $item)
405
-    {
406
-        $reg_start = $item->get_ticket_with_earliest_start_time();
407
-        echo ! empty($reg_start)
408
-            ? $reg_start->get_i18n_datetime('TKT_start_date')
409
-            : esc_html__('No Tickets have been setup for this Event', 'event_espresso');
410
-        //display in user's timezone?
411
-        echo ! empty($reg_start)
412
-            ? $reg_start->display_in_my_timezone(
413
-                'TKT_start_date',
414
-                'get_i18n_datetime',
415
-                '',
416
-                'My Timezone: '
417
-            )
418
-            : '';
419
-    }
420
-
421
-
422
-    /**
423
-     * @param EE_Event $item
424
-     * @return int|string
425
-     * @throws EE_Error
426
-     */
427
-    public function column_attendees(EE_Event $item)
428
-    {
429
-        $attendees_query_args = array(
430
-            'action'   => 'default',
431
-            'event_id' => $item->ID(),
432
-        );
433
-        $attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
434
-        $registered_attendees = EEM_Registration::instance()->get_event_registration_count($item->ID());
435
-        return EE_Registry::instance()->CAP->current_user_can(
436
-            'ee_read_event',
437
-            'espresso_registrations_view_registration',
438
-            $item->ID()
439
-        )
440
-            && EE_Registry::instance()->CAP->current_user_can(
441
-                'ee_read_registrations',
442
-                'espresso_registrations_view_registration'
443
-            )
444
-            ? '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>'
445
-            : $registered_attendees;
446
-    }
447
-
448
-
449
-    /**
450
-     * @param EE_Event $item
451
-     * @return float
452
-     * @throws EE_Error
453
-     */
454
-    public function column_tkts_sold(EE_Event $item)
455
-    {
456
-        return EEM_Ticket::instance()->sum(array(array('Datetime.EVT_ID' => $item->ID())), 'TKT_sold');
457
-    }
458
-
459
-
460
-    /**
461
-     * @param EE_Event $item
462
-     * @return string
463
-     * @throws EE_Error
464
-     */
465
-    public function column_actions(EE_Event $item)
466
-    {
467
-        //todo: remove when attendees is active
468
-        if (! defined('REG_ADMIN_URL')) {
469
-            define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
470
-        }
471
-        $actionlinks = array();
472
-
473
-        $view_link = get_permalink($item->ID());
474
-
475
-        $actionlinks[] = '<a href="' . $view_link . '"'
476
-                         . ' title="' . esc_attr__('View Event', 'event_espresso') . '" target="_blank">';
477
-        $actionlinks[] = '<div class="dashicons dashicons-search"></div></a>';
478
-
479
-        if (EE_Registry::instance()->CAP->current_user_can(
480
-            'ee_edit_event',
481
-            'espresso_events_edit',
482
-            $item->ID()
483
-        )) {
484
-            $edit_query_args = array(
485
-                'action' => 'edit',
486
-                'post'   => $item->ID(),
487
-            );
488
-            $edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
489
-            $actionlinks[]   = '<a href="' . $edit_link . '"'
490
-                               . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
491
-                               . '<div class="ee-icon ee-icon-calendar-edit"></div>'
492
-                               . '</a>';
493
-        }
494
-
495
-        if (EE_Registry::instance()->CAP->current_user_can(
496
-            'ee_read_event',
497
-            'espresso_registrations_view_registration',
498
-            $item->ID()
499
-        )
500
-            && EE_Registry::instance()->CAP->current_user_can(
501
-                'ee_read_registrations',
502
-                'espresso_registrations_view_registration'
503
-            )
504
-        ) {
505
-            $attendees_query_args = array(
506
-                'action'   => 'default',
507
-                'event_id' => $item->ID(),
508
-            );
509
-            $attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
510
-            $actionlinks[]        = '<a href="' . $attendees_link . '"'
511
-                                    . ' title="' . esc_attr__('View Registrants', 'event_espresso') . '">'
512
-                                    . '<div class="dashicons dashicons-groups"></div>'
513
-                                    . '</a>';
514
-        }
515
-
516
-        $actionlinks = apply_filters(
517
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
518
-            $actionlinks,
519
-            $item
520
-        );
521
-
522
-        return $this->_action_string(implode("\n\t", $actionlinks), $item, 'div');
523
-    }
16
+	/**
17
+	 * @var EE_Datetime
18
+	 */
19
+	private $_dtt;
20
+
21
+
22
+	/**
23
+	 * Initial setup of data properties for the list table.
24
+	 */
25
+	protected function _setup_data()
26
+	{
27
+		$this->_data           = $this->_admin_page->get_events($this->_per_page, $this->_current_page);
28
+		$this->_all_data_count = $this->_admin_page->get_events(0, 0, true);
29
+	}
30
+
31
+
32
+	/**
33
+	 * Set up of additional properties for the list table.
34
+	 */
35
+	protected function _set_properties()
36
+	{
37
+		$this->_wp_list_args = array(
38
+			'singular' => esc_html__('event', 'event_espresso'),
39
+			'plural'   => esc_html__('events', 'event_espresso'),
40
+			'ajax'     => true, //for now
41
+			'screen'   => $this->_admin_page->get_current_screen()->id,
42
+		);
43
+
44
+
45
+		$this->_columns = array(
46
+			'cb'              => '<input type="checkbox" />',
47
+			'id'              => esc_html__('ID', 'event_espresso'),
48
+			'name'            => esc_html__('Name', 'event_espresso'),
49
+			'author'          => esc_html__('Author', 'event_espresso'),
50
+			'venue'           => esc_html__('Venue', 'event_espresso'),
51
+			'start_date_time' => esc_html__('Event Start', 'event_espresso'),
52
+			'reg_begins'      => esc_html__('On Sale', 'event_espresso'),
53
+			'attendees'       => '<span class="dashicons dashicons-groups ee-icon-color-ee-green ee-icon-size-20">'
54
+								 . '</span>',
55
+			//'tkts_sold' => esc_html__('Tickets Sold', 'event_espresso'),
56
+			'actions'         => esc_html__('Actions', 'event_espresso'),
57
+		);
58
+
59
+
60
+		$this->_sortable_columns = array(
61
+			'id'              => array('EVT_ID' => true),
62
+			'name'            => array('EVT_name' => false),
63
+			'author'          => array('EVT_wp_user' => false),
64
+			'venue'           => array('Venue.VNU_name' => false),
65
+			'start_date_time' => array('Datetime.DTT_EVT_start' => false),
66
+			'reg_begins'      => array('Datetime.Ticket.TKT_start_date' => false),
67
+		);
68
+
69
+		$this->_primary_column = 'id';
70
+
71
+		$this->_hidden_columns = array('author');
72
+	}
73
+
74
+
75
+	/**
76
+	 * @return array
77
+	 */
78
+	protected function _get_table_filters()
79
+	{
80
+		return array(); //no filters with decaf
81
+	}
82
+
83
+
84
+	/**
85
+	 * Setup of views properties.
86
+	 */
87
+	protected function _add_view_counts()
88
+	{
89
+		$this->_views['all']['count']   = $this->_admin_page->total_events();
90
+		$this->_views['draft']['count'] = $this->_admin_page->total_events_draft();
91
+		if (EE_Registry::instance()->CAP->current_user_can(
92
+			'ee_delete_events',
93
+			'espresso_events_trash_events'
94
+		)) {
95
+			$this->_views['trash']['count'] = $this->_admin_page->total_trashed_events();
96
+		}
97
+	}
98
+
99
+
100
+	/**
101
+	 * @param EE_Event $item
102
+	 * @return string
103
+	 * @throws EE_Error
104
+	 */
105
+	protected function _get_row_class($item)
106
+	{
107
+		$class = parent::_get_row_class($item);
108
+		//add status class
109
+		$class .= $item instanceof EE_Event ? ' ee-status-strip event-status-' . $item->get_active_status() : '';
110
+		if ($this->_has_checkbox_column) {
111
+			$class .= ' has-checkbox-column';
112
+		}
113
+		return $class;
114
+	}
115
+
116
+
117
+	/**
118
+	 * @param EE_Event $item
119
+	 * @return string
120
+	 * @throws EE_Error
121
+	 */
122
+	public function column_status(EE_Event $item)
123
+	{
124
+		return '<span class="ee-status-strip ee-status-strip-td event-status-'
125
+			   . $item->get_active_status()
126
+			   . '"></span>';
127
+	}
128
+
129
+
130
+	/**
131
+	 * @param  EE_Event $item
132
+	 * @return string
133
+	 * @throws EE_Error
134
+	 */
135
+	public function column_cb($item)
136
+	{
137
+		if (! $item instanceof EE_Event) {
138
+			return '';
139
+		}
140
+		$this->_dtt = $item->primary_datetime(); //set this for use in other columns
141
+
142
+		//does event have any attached registrations?
143
+		$regs = $item->count_related('Registration');
144
+		return $regs > 0 && $this->_view == 'trash'
145
+			? '<span class="ee-lock-icon"></span>'
146
+			: sprintf(
147
+				'<input type="checkbox" name="EVT_IDs[]" value="%s" />',
148
+				$item->ID()
149
+			);
150
+	}
151
+
152
+
153
+	/**
154
+	 * @param EE_Event $item
155
+	 * @return mixed|string
156
+	 * @throws EE_Error
157
+	 */
158
+	public function column_id(EE_Event $item)
159
+	{
160
+		$content = $item->ID();
161
+		$content .= '  <span class="show-on-mobile-view-only">' . $item->name() . '</span>';
162
+		return $content;
163
+	}
164
+
165
+
166
+	/**
167
+	 * @param EE_Event $item
168
+	 * @return string
169
+	 * @throws EE_Error
170
+	 */
171
+	public function column_name(EE_Event $item)
172
+	{
173
+		$edit_query_args = array(
174
+			'action' => 'edit',
175
+			'post'   => $item->ID(),
176
+		);
177
+		$edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
178
+		$actions         = $this->_column_name_action_setup($item);
179
+		$status          = ''; //$item->status() !== 'publish' ? ' (' . $item->status() . ')' : '';
180
+		$content         = '<strong><a class="row-title" href="'
181
+						   . $edit_link . '">'
182
+						   . $item->name()
183
+						   . '</a></strong>'
184
+						   . $status;
185
+		$content         .= '<br><span class="ee-status-text-small">'
186
+							. EEH_Template::pretty_status(
187
+								$item->get_active_status(),
188
+								false,
189
+								'sentence'
190
+							)
191
+							. '</span>';
192
+		$content         .= $this->row_actions($actions);
193
+		return $content;
194
+	}
195
+
196
+
197
+	/**
198
+	 * Just a method for setting up the actions for the name column
199
+	 *
200
+	 * @param EE_Event $item
201
+	 * @return array array of actions
202
+	 * @throws EE_Error
203
+	 */
204
+	protected function _column_name_action_setup(EE_Event $item)
205
+	{
206
+		//todo: remove when attendees is active
207
+		if (! defined('REG_ADMIN_URL')) {
208
+			define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
209
+		}
210
+
211
+		$actions = array();
212
+
213
+		if (EE_Registry::instance()->CAP->current_user_can(
214
+			'ee_edit_event',
215
+			'espresso_events_edit',
216
+			$item->ID()
217
+		)) {
218
+			$edit_query_args = array(
219
+				'action' => 'edit',
220
+				'post'   => $item->ID(),
221
+			);
222
+			$edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
223
+			$actions['edit'] = '<a href="' . $edit_link . '"'
224
+							   . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
225
+							   . esc_html__('Edit', 'event_espresso')
226
+							   . '</a>';
227
+
228
+		}
229
+
230
+		if (EE_Registry::instance()->CAP->current_user_can(
231
+			'ee_read_event',
232
+			'espresso_registrations_view_registration',
233
+			$item->ID()
234
+		)
235
+			&& EE_Registry::instance()->CAP->current_user_can(
236
+				'ee_read_registrations',
237
+				'espresso_registrations_view_registration'
238
+			)
239
+		) {
240
+			$attendees_query_args = array(
241
+				'action'   => 'default',
242
+				'event_id' => $item->ID(),
243
+			);
244
+			$attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
245
+			$actions['attendees'] = '<a href="' . $attendees_link . '"'
246
+									. ' title="' . esc_attr__('View Registrations', 'event_espresso') . '">'
247
+									. esc_html__('Registrations', 'event_espresso')
248
+									. '</a>';
249
+		}
250
+
251
+		if (EE_Registry::instance()->CAP->current_user_can(
252
+			'ee_delete_event',
253
+			'espresso_events_trash_event',
254
+			$item->ID()
255
+		)) {
256
+			$trash_event_query_args = array(
257
+				'action' => 'trash_event',
258
+				'EVT_ID' => $item->ID(),
259
+			);
260
+			$trash_event_link       = EE_Admin_Page::add_query_args_and_nonce(
261
+				$trash_event_query_args,
262
+				EVENTS_ADMIN_URL
263
+			);
264
+		}
265
+
266
+		if (EE_Registry::instance()->CAP->current_user_can(
267
+			'ee_delete_event',
268
+			'espresso_events_restore_event',
269
+			$item->ID()
270
+		)) {
271
+			$restore_event_query_args = array(
272
+				'action' => 'restore_event',
273
+				'EVT_ID' => $item->ID(),
274
+			);
275
+			$restore_event_link       = EE_Admin_Page::add_query_args_and_nonce(
276
+				$restore_event_query_args,
277
+				EVENTS_ADMIN_URL
278
+			);
279
+		}
280
+
281
+		if (EE_Registry::instance()->CAP->current_user_can(
282
+			'ee_delete_event',
283
+			'espresso_events_delete_event',
284
+			$item->ID()
285
+		)) {
286
+			$delete_event_query_args = array(
287
+				'action' => 'delete_event',
288
+				'EVT_ID' => $item->ID(),
289
+			);
290
+			$delete_event_link       = EE_Admin_Page::add_query_args_and_nonce(
291
+				$delete_event_query_args,
292
+				EVENTS_ADMIN_URL
293
+			);
294
+		}
295
+
296
+		$view_link = get_permalink($item->ID());
297
+
298
+		$actions['view'] = '<a href="' . $view_link . '"'
299
+						   . ' title="' . esc_attr__('View Event', 'event_espresso') . '">'
300
+						   . esc_html__('View', 'event_espresso')
301
+						   . '</a>';
302
+
303
+		switch ($item->get('status')) {
304
+			case 'trash':
305
+				if (EE_Registry::instance()->CAP->current_user_can(
306
+					'ee_delete_event',
307
+					'espresso_events_restore_event',
308
+					$item->ID()
309
+				)) {
310
+					$actions['restore_from_trash'] = '<a href="' . $restore_event_link . '"'
311
+													 . ' title="' . esc_attr__('Restore from Trash', 'event_espresso')
312
+													 . '">'
313
+													 . esc_html__('Restore from Trash', 'event_espresso')
314
+													 . '</a>';
315
+				}
316
+				if ($item->count_related('Registration') === 0
317
+					&& EE_Registry::instance()->CAP->current_user_can(
318
+						'ee_delete_event',
319
+						'espresso_events_delete_event',
320
+						$item->ID()
321
+					)) {
322
+					$actions['delete'] = '<a href="' . $delete_event_link . '"'
323
+										 . ' title="' . esc_attr__('Delete Permanently', 'event_espresso') . '">'
324
+										 . esc_html__('Delete Permanently', 'event_espresso')
325
+										 . '</a>';
326
+				}
327
+				break;
328
+			default:
329
+				if (EE_Registry::instance()->CAP->current_user_can(
330
+					'ee_delete_event',
331
+					'espresso_events_trash_event',
332
+					$item->ID()
333
+				)) {
334
+					$actions['move to trash'] = '<a href="' . $trash_event_link . '"'
335
+												. ' title="' . esc_attr__('Trash Event', 'event_espresso') . '">'
336
+												. esc_html__('Trash', 'event_espresso')
337
+												. '</a>';
338
+				}
339
+		}
340
+		return $actions;
341
+	}
342
+
343
+
344
+	/**
345
+	 * @param EE_Event $item
346
+	 * @return string
347
+	 * @throws EE_Error
348
+	 */
349
+	public function column_author(EE_Event $item)
350
+	{
351
+		//user author info
352
+		$event_author = get_userdata($item->wp_user());
353
+		$gravatar     = get_avatar($item->wp_user(), '15');
354
+		//filter link
355
+		$query_args = array(
356
+			'action'      => 'default',
357
+			'EVT_wp_user' => $item->wp_user(),
358
+		);
359
+		$filter_url = EE_Admin_Page::add_query_args_and_nonce($query_args, EVENTS_ADMIN_URL);
360
+		return $gravatar . '  <a href="' . $filter_url . '"'
361
+			   . ' title="' . esc_attr__('Click to filter events by this author.', 'event_espresso') . '">'
362
+			   . $event_author->display_name
363
+			   . '</a>';
364
+	}
365
+
366
+
367
+	/**
368
+	 * @param EE_Event $item
369
+	 * @return string
370
+	 * @throws EE_Error
371
+	 */
372
+	public function column_venue(EE_Event $item)
373
+	{
374
+		$venue = $item->get_first_related('Venue');
375
+		return ! empty($venue) ? $venue->name() : '';
376
+	}
377
+
378
+
379
+	/**
380
+	 * @param EE_Event $item
381
+	 * @throws EE_Error
382
+	 */
383
+	public function column_start_date_time(EE_Event $item)
384
+	{
385
+		echo ! empty($this->_dtt)
386
+			? $this->_dtt->get_i18n_datetime('DTT_EVT_start')
387
+			: esc_html__('No Date was saved for this Event', 'event_espresso');
388
+		//display in user's timezone?
389
+		echo ! empty($this->_dtt)
390
+			? $this->_dtt->display_in_my_timezone(
391
+				'DTT_EVT_start',
392
+				'get_i18n_datetime',
393
+				'',
394
+				'My Timezone: '
395
+			)
396
+			: '';
397
+	}
398
+
399
+
400
+	/**
401
+	 * @param EE_Event $item
402
+	 * @throws EE_Error
403
+	 */
404
+	public function column_reg_begins(EE_Event $item)
405
+	{
406
+		$reg_start = $item->get_ticket_with_earliest_start_time();
407
+		echo ! empty($reg_start)
408
+			? $reg_start->get_i18n_datetime('TKT_start_date')
409
+			: esc_html__('No Tickets have been setup for this Event', 'event_espresso');
410
+		//display in user's timezone?
411
+		echo ! empty($reg_start)
412
+			? $reg_start->display_in_my_timezone(
413
+				'TKT_start_date',
414
+				'get_i18n_datetime',
415
+				'',
416
+				'My Timezone: '
417
+			)
418
+			: '';
419
+	}
420
+
421
+
422
+	/**
423
+	 * @param EE_Event $item
424
+	 * @return int|string
425
+	 * @throws EE_Error
426
+	 */
427
+	public function column_attendees(EE_Event $item)
428
+	{
429
+		$attendees_query_args = array(
430
+			'action'   => 'default',
431
+			'event_id' => $item->ID(),
432
+		);
433
+		$attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
434
+		$registered_attendees = EEM_Registration::instance()->get_event_registration_count($item->ID());
435
+		return EE_Registry::instance()->CAP->current_user_can(
436
+			'ee_read_event',
437
+			'espresso_registrations_view_registration',
438
+			$item->ID()
439
+		)
440
+			&& EE_Registry::instance()->CAP->current_user_can(
441
+				'ee_read_registrations',
442
+				'espresso_registrations_view_registration'
443
+			)
444
+			? '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>'
445
+			: $registered_attendees;
446
+	}
447
+
448
+
449
+	/**
450
+	 * @param EE_Event $item
451
+	 * @return float
452
+	 * @throws EE_Error
453
+	 */
454
+	public function column_tkts_sold(EE_Event $item)
455
+	{
456
+		return EEM_Ticket::instance()->sum(array(array('Datetime.EVT_ID' => $item->ID())), 'TKT_sold');
457
+	}
458
+
459
+
460
+	/**
461
+	 * @param EE_Event $item
462
+	 * @return string
463
+	 * @throws EE_Error
464
+	 */
465
+	public function column_actions(EE_Event $item)
466
+	{
467
+		//todo: remove when attendees is active
468
+		if (! defined('REG_ADMIN_URL')) {
469
+			define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
470
+		}
471
+		$actionlinks = array();
472
+
473
+		$view_link = get_permalink($item->ID());
474
+
475
+		$actionlinks[] = '<a href="' . $view_link . '"'
476
+						 . ' title="' . esc_attr__('View Event', 'event_espresso') . '" target="_blank">';
477
+		$actionlinks[] = '<div class="dashicons dashicons-search"></div></a>';
478
+
479
+		if (EE_Registry::instance()->CAP->current_user_can(
480
+			'ee_edit_event',
481
+			'espresso_events_edit',
482
+			$item->ID()
483
+		)) {
484
+			$edit_query_args = array(
485
+				'action' => 'edit',
486
+				'post'   => $item->ID(),
487
+			);
488
+			$edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
489
+			$actionlinks[]   = '<a href="' . $edit_link . '"'
490
+							   . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
491
+							   . '<div class="ee-icon ee-icon-calendar-edit"></div>'
492
+							   . '</a>';
493
+		}
494
+
495
+		if (EE_Registry::instance()->CAP->current_user_can(
496
+			'ee_read_event',
497
+			'espresso_registrations_view_registration',
498
+			$item->ID()
499
+		)
500
+			&& EE_Registry::instance()->CAP->current_user_can(
501
+				'ee_read_registrations',
502
+				'espresso_registrations_view_registration'
503
+			)
504
+		) {
505
+			$attendees_query_args = array(
506
+				'action'   => 'default',
507
+				'event_id' => $item->ID(),
508
+			);
509
+			$attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
510
+			$actionlinks[]        = '<a href="' . $attendees_link . '"'
511
+									. ' title="' . esc_attr__('View Registrants', 'event_espresso') . '">'
512
+									. '<div class="dashicons dashicons-groups"></div>'
513
+									. '</a>';
514
+		}
515
+
516
+		$actionlinks = apply_filters(
517
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
518
+			$actionlinks,
519
+			$item
520
+		);
521
+
522
+		return $this->_action_string(implode("\n\t", $actionlinks), $item, 'div');
523
+	}
524 524
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
     {
107 107
         $class = parent::_get_row_class($item);
108 108
         //add status class
109
-        $class .= $item instanceof EE_Event ? ' ee-status-strip event-status-' . $item->get_active_status() : '';
109
+        $class .= $item instanceof EE_Event ? ' ee-status-strip event-status-'.$item->get_active_status() : '';
110 110
         if ($this->_has_checkbox_column) {
111 111
             $class .= ' has-checkbox-column';
112 112
         }
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
      */
135 135
     public function column_cb($item)
136 136
     {
137
-        if (! $item instanceof EE_Event) {
137
+        if ( ! $item instanceof EE_Event) {
138 138
             return '';
139 139
         }
140 140
         $this->_dtt = $item->primary_datetime(); //set this for use in other columns
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
     public function column_id(EE_Event $item)
159 159
     {
160 160
         $content = $item->ID();
161
-        $content .= '  <span class="show-on-mobile-view-only">' . $item->name() . '</span>';
161
+        $content .= '  <span class="show-on-mobile-view-only">'.$item->name().'</span>';
162 162
         return $content;
163 163
     }
164 164
 
@@ -178,18 +178,18 @@  discard block
 block discarded – undo
178 178
         $actions         = $this->_column_name_action_setup($item);
179 179
         $status          = ''; //$item->status() !== 'publish' ? ' (' . $item->status() . ')' : '';
180 180
         $content         = '<strong><a class="row-title" href="'
181
-                           . $edit_link . '">'
181
+                           . $edit_link.'">'
182 182
                            . $item->name()
183 183
                            . '</a></strong>'
184 184
                            . $status;
185
-        $content         .= '<br><span class="ee-status-text-small">'
185
+        $content .= '<br><span class="ee-status-text-small">'
186 186
                             . EEH_Template::pretty_status(
187 187
                                 $item->get_active_status(),
188 188
                                 false,
189 189
                                 'sentence'
190 190
                             )
191 191
                             . '</span>';
192
-        $content         .= $this->row_actions($actions);
192
+        $content .= $this->row_actions($actions);
193 193
         return $content;
194 194
     }
195 195
 
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
     protected function _column_name_action_setup(EE_Event $item)
205 205
     {
206 206
         //todo: remove when attendees is active
207
-        if (! defined('REG_ADMIN_URL')) {
207
+        if ( ! defined('REG_ADMIN_URL')) {
208 208
             define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
209 209
         }
210 210
 
@@ -220,8 +220,8 @@  discard block
 block discarded – undo
220 220
                 'post'   => $item->ID(),
221 221
             );
222 222
             $edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
223
-            $actions['edit'] = '<a href="' . $edit_link . '"'
224
-                               . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
223
+            $actions['edit'] = '<a href="'.$edit_link.'"'
224
+                               . ' title="'.esc_attr__('Edit Event', 'event_espresso').'">'
225 225
                                . esc_html__('Edit', 'event_espresso')
226 226
                                . '</a>';
227 227
 
@@ -242,8 +242,8 @@  discard block
 block discarded – undo
242 242
                 'event_id' => $item->ID(),
243 243
             );
244 244
             $attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
245
-            $actions['attendees'] = '<a href="' . $attendees_link . '"'
246
-                                    . ' title="' . esc_attr__('View Registrations', 'event_espresso') . '">'
245
+            $actions['attendees'] = '<a href="'.$attendees_link.'"'
246
+                                    . ' title="'.esc_attr__('View Registrations', 'event_espresso').'">'
247 247
                                     . esc_html__('Registrations', 'event_espresso')
248 248
                                     . '</a>';
249 249
         }
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
                 'action' => 'trash_event',
258 258
                 'EVT_ID' => $item->ID(),
259 259
             );
260
-            $trash_event_link       = EE_Admin_Page::add_query_args_and_nonce(
260
+            $trash_event_link = EE_Admin_Page::add_query_args_and_nonce(
261 261
                 $trash_event_query_args,
262 262
                 EVENTS_ADMIN_URL
263 263
             );
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
                 'action' => 'restore_event',
273 273
                 'EVT_ID' => $item->ID(),
274 274
             );
275
-            $restore_event_link       = EE_Admin_Page::add_query_args_and_nonce(
275
+            $restore_event_link = EE_Admin_Page::add_query_args_and_nonce(
276 276
                 $restore_event_query_args,
277 277
                 EVENTS_ADMIN_URL
278 278
             );
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
                 'action' => 'delete_event',
288 288
                 'EVT_ID' => $item->ID(),
289 289
             );
290
-            $delete_event_link       = EE_Admin_Page::add_query_args_and_nonce(
290
+            $delete_event_link = EE_Admin_Page::add_query_args_and_nonce(
291 291
                 $delete_event_query_args,
292 292
                 EVENTS_ADMIN_URL
293 293
             );
@@ -295,8 +295,8 @@  discard block
 block discarded – undo
295 295
 
296 296
         $view_link = get_permalink($item->ID());
297 297
 
298
-        $actions['view'] = '<a href="' . $view_link . '"'
299
-                           . ' title="' . esc_attr__('View Event', 'event_espresso') . '">'
298
+        $actions['view'] = '<a href="'.$view_link.'"'
299
+                           . ' title="'.esc_attr__('View Event', 'event_espresso').'">'
300 300
                            . esc_html__('View', 'event_espresso')
301 301
                            . '</a>';
302 302
 
@@ -307,8 +307,8 @@  discard block
 block discarded – undo
307 307
                     'espresso_events_restore_event',
308 308
                     $item->ID()
309 309
                 )) {
310
-                    $actions['restore_from_trash'] = '<a href="' . $restore_event_link . '"'
311
-                                                     . ' title="' . esc_attr__('Restore from Trash', 'event_espresso')
310
+                    $actions['restore_from_trash'] = '<a href="'.$restore_event_link.'"'
311
+                                                     . ' title="'.esc_attr__('Restore from Trash', 'event_espresso')
312 312
                                                      . '">'
313 313
                                                      . esc_html__('Restore from Trash', 'event_espresso')
314 314
                                                      . '</a>';
@@ -319,8 +319,8 @@  discard block
 block discarded – undo
319 319
                         'espresso_events_delete_event',
320 320
                         $item->ID()
321 321
                     )) {
322
-                    $actions['delete'] = '<a href="' . $delete_event_link . '"'
323
-                                         . ' title="' . esc_attr__('Delete Permanently', 'event_espresso') . '">'
322
+                    $actions['delete'] = '<a href="'.$delete_event_link.'"'
323
+                                         . ' title="'.esc_attr__('Delete Permanently', 'event_espresso').'">'
324 324
                                          . esc_html__('Delete Permanently', 'event_espresso')
325 325
                                          . '</a>';
326 326
                 }
@@ -331,8 +331,8 @@  discard block
 block discarded – undo
331 331
                     'espresso_events_trash_event',
332 332
                     $item->ID()
333 333
                 )) {
334
-                    $actions['move to trash'] = '<a href="' . $trash_event_link . '"'
335
-                                                . ' title="' . esc_attr__('Trash Event', 'event_espresso') . '">'
334
+                    $actions['move to trash'] = '<a href="'.$trash_event_link.'"'
335
+                                                . ' title="'.esc_attr__('Trash Event', 'event_espresso').'">'
336 336
                                                 . esc_html__('Trash', 'event_espresso')
337 337
                                                 . '</a>';
338 338
                 }
@@ -357,8 +357,8 @@  discard block
 block discarded – undo
357 357
             'EVT_wp_user' => $item->wp_user(),
358 358
         );
359 359
         $filter_url = EE_Admin_Page::add_query_args_and_nonce($query_args, EVENTS_ADMIN_URL);
360
-        return $gravatar . '  <a href="' . $filter_url . '"'
361
-               . ' title="' . esc_attr__('Click to filter events by this author.', 'event_espresso') . '">'
360
+        return $gravatar.'  <a href="'.$filter_url.'"'
361
+               . ' title="'.esc_attr__('Click to filter events by this author.', 'event_espresso').'">'
362 362
                . $event_author->display_name
363 363
                . '</a>';
364 364
     }
@@ -441,7 +441,7 @@  discard block
 block discarded – undo
441 441
                 'ee_read_registrations',
442 442
                 'espresso_registrations_view_registration'
443 443
             )
444
-            ? '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>'
444
+            ? '<a href="'.$attendees_link.'">'.$registered_attendees.'</a>'
445 445
             : $registered_attendees;
446 446
     }
447 447
 
@@ -465,15 +465,15 @@  discard block
 block discarded – undo
465 465
     public function column_actions(EE_Event $item)
466 466
     {
467 467
         //todo: remove when attendees is active
468
-        if (! defined('REG_ADMIN_URL')) {
468
+        if ( ! defined('REG_ADMIN_URL')) {
469 469
             define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
470 470
         }
471 471
         $actionlinks = array();
472 472
 
473 473
         $view_link = get_permalink($item->ID());
474 474
 
475
-        $actionlinks[] = '<a href="' . $view_link . '"'
476
-                         . ' title="' . esc_attr__('View Event', 'event_espresso') . '" target="_blank">';
475
+        $actionlinks[] = '<a href="'.$view_link.'"'
476
+                         . ' title="'.esc_attr__('View Event', 'event_espresso').'" target="_blank">';
477 477
         $actionlinks[] = '<div class="dashicons dashicons-search"></div></a>';
478 478
 
479 479
         if (EE_Registry::instance()->CAP->current_user_can(
@@ -486,8 +486,8 @@  discard block
 block discarded – undo
486 486
                 'post'   => $item->ID(),
487 487
             );
488 488
             $edit_link       = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
489
-            $actionlinks[]   = '<a href="' . $edit_link . '"'
490
-                               . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
489
+            $actionlinks[]   = '<a href="'.$edit_link.'"'
490
+                               . ' title="'.esc_attr__('Edit Event', 'event_espresso').'">'
491 491
                                . '<div class="ee-icon ee-icon-calendar-edit"></div>'
492 492
                                . '</a>';
493 493
         }
@@ -507,8 +507,8 @@  discard block
 block discarded – undo
507 507
                 'event_id' => $item->ID(),
508 508
             );
509 509
             $attendees_link       = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
510
-            $actionlinks[]        = '<a href="' . $attendees_link . '"'
511
-                                    . ' title="' . esc_attr__('View Registrants', 'event_espresso') . '">'
510
+            $actionlinks[]        = '<a href="'.$attendees_link.'"'
511
+                                    . ' title="'.esc_attr__('View Registrants', 'event_espresso').'">'
512 512
                                     . '<div class="dashicons dashicons-groups"></div>'
513 513
                                     . '</a>';
514 514
         }
Please login to merge, or discard this patch.
core/EE_Capabilities.core.php 2 patches
Indentation   +1368 added lines, -1368 removed lines patch added patch discarded remove patch
@@ -18,980 +18,980 @@  discard block
 block discarded – undo
18 18
 final class EE_Capabilities extends EE_Base
19 19
 {
20 20
 
21
-    /**
22
-     * the name of the wp option used to store caps previously initialized
23
-     */
24
-    const option_name = 'ee_caps_initialized';
25
-
26
-    /**
27
-     * instance of EE_Capabilities object
28
-     *
29
-     * @var EE_Capabilities
30
-     */
31
-    private static $_instance;
32
-
33
-
34
-    /**
35
-     * This is a map of caps that correspond to a default WP_Role.
36
-     * Array is indexed by Role and values are ee capabilities.
37
-     *
38
-     * @since 4.5.0
39
-     *
40
-     * @var array
41
-     */
42
-    private $capabilities_map = array();
43
-
44
-    /**
45
-     * This used to hold an array of EE_Meta_Capability_Map objects
46
-     * that define the granular capabilities mapped to for a user depending on context.
47
-     *
48
-     * @var EE_Meta_Capability_Map[]
49
-     */
50
-    private $_meta_caps = array();
51
-
52
-    /**
53
-     * The internal $capabilities_map needs to be initialized before it can be used.
54
-     * This flag tracks whether that has happened or not.
55
-     * But for this to work, we need three states to indicate:
56
-     *      initialization has not occurred at all
57
-     *      initialization has started but is not complete
58
-     *      initialization is complete
59
-     * The reason this is needed is because the addCaps() method
60
-     * normally requires the $capabilities_map to be initialized,
61
-     * but is also used during the initialization process.
62
-     * So:
63
-     *      If initialized === null, init_caps() will be called before any other methods will run.
64
-     *      If initialized === false, then init_caps() is in the process of running it's logic.
65
-     *      If initialized === true, then init_caps() has completed the initialization process.
66
-     *
67
-     * @var boolean|null $initialized
68
-     */
69
-    private $initialized;
70
-
71
-    /**
72
-     * @var boolean $reset
73
-     */
74
-    private $reset = false;
75
-
76
-
77
-
78
-    /**
79
-     * singleton method used to instantiate class object
80
-     *
81
-     * @since 4.5.0
82
-     *
83
-     * @return EE_Capabilities
84
-     */
85
-    public static function instance()
86
-    {
87
-        //check if instantiated, and if not do so.
88
-        if (! self::$_instance instanceof EE_Capabilities) {
89
-            self::$_instance = new self();
90
-        }
91
-        return self::$_instance;
92
-    }
93
-
94
-
95
-
96
-    /**
97
-     * private constructor
98
-     *
99
-     * @since 4.5.0
100
-     */
101
-    private function __construct()
102
-    {
103
-    }
104
-
105
-
106
-
107
-    /**
108
-     * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
109
-     *
110
-     * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
111
-     *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
112
-     *                    ensures that they are up to date.
113
-     *
114
-     * @since 4.5.0
115
-     * @return bool
116
-     * @throws EE_Error
117
-     */
118
-    public function init_caps($reset = false)
119
-    {
120
-        if(! EE_Maintenance_Mode::instance()->models_can_query()){
121
-            return false;
122
-        }
123
-        $this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
124
-        // if reset, then completely delete the cache option and clear the $capabilities_map property.
125
-        if ($this->reset) {
126
-            $this->initialized = null;
127
-            $this->capabilities_map = array();
128
-            delete_option(self::option_name);
129
-        }
130
-        if ($this->initialized === null) {
131
-            $this->initialized = false;
132
-            do_action(
133
-                'AHEE__EE_Capabilities__init_caps__before_initialization',
134
-                $this->reset
135
-            );
136
-            $this->addCaps($this->_init_caps_map());
137
-            $this->_set_meta_caps();
138
-            do_action(
139
-                'AHEE__EE_Capabilities__init_caps__after_initialization',
140
-                $this->capabilities_map
141
-            );
142
-            $this->initialized = true;
143
-        }
144
-        // reset $this->reset so that it's not stuck on true if init_caps() gets called again
145
-        $this->reset = false;
146
-        return true;
147
-    }
148
-
149
-
150
-
151
-    /**
152
-     * This sets the meta caps property.
153
-     *
154
-     * @since 4.5.0
155
-     * @return void
156
-     * @throws EE_Error
157
-     */
158
-    private function _set_meta_caps()
159
-    {
160
-        // get default meta caps and filter the returned array
161
-        $this->_meta_caps = apply_filters(
162
-            'FHEE__EE_Capabilities___set_meta_caps__meta_caps',
163
-            $this->_get_default_meta_caps_array()
164
-        );
165
-        //add filter for map_meta_caps but only if models can query.
166
-        if (! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
167
-            add_filter('map_meta_cap', array($this, 'map_meta_caps'), 10, 4);
168
-        }
169
-    }
170
-
171
-
172
-
173
-    /**
174
-     * This builds and returns the default meta_caps array only once.
175
-     *
176
-     * @since  4.8.28.rc.012
177
-     * @return array
178
-     * @throws EE_Error
179
-     */
180
-    private function _get_default_meta_caps_array()
181
-    {
182
-        static $default_meta_caps = array();
183
-        // make sure we're only ever initializing the default _meta_caps array once if it's empty.
184
-        if (empty($default_meta_caps)) {
185
-            $default_meta_caps = array(
186
-                //edits
187
-                new EE_Meta_Capability_Map_Edit(
188
-                    'ee_edit_event',
189
-                    array('Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events')
190
-                ),
191
-                new EE_Meta_Capability_Map_Edit(
192
-                    'ee_edit_venue',
193
-                    array('Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues')
194
-                ),
195
-                new EE_Meta_Capability_Map_Edit(
196
-                    'ee_edit_registration',
197
-                    array('Registration', '', 'ee_edit_others_registrations', '')
198
-                ),
199
-                new EE_Meta_Capability_Map_Edit(
200
-                    'ee_edit_checkin',
201
-                    array('Registration', '', 'ee_edit_others_checkins', '')
202
-                ),
203
-                new EE_Meta_Capability_Map_Messages_Cap(
204
-                    'ee_edit_message',
205
-                    array('Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages')
206
-                ),
207
-                new EE_Meta_Capability_Map_Edit(
208
-                    'ee_edit_default_ticket',
209
-                    array('Ticket', '', 'ee_edit_others_default_tickets', '')
210
-                ),
211
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
212
-                    'ee_edit_question',
213
-                    array('Question', '', '', 'ee_edit_system_questions')
214
-                ),
215
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
216
-                    'ee_edit_question_group',
217
-                    array('Question_Group', '', '', 'ee_edit_system_question_groups')
218
-                ),
219
-                new EE_Meta_Capability_Map_Edit(
220
-                    'ee_edit_payment_method',
221
-                    array('Payment_Method', '', 'ee_edit_others_payment_methods', '')
222
-                ),
223
-                //reads
224
-                new EE_Meta_Capability_Map_Read(
225
-                    'ee_read_event',
226
-                    array('Event', '', 'ee_read_others_events', 'ee_read_private_events')
227
-                ),
228
-                new EE_Meta_Capability_Map_Read(
229
-                    'ee_read_venue',
230
-                    array('Venue', '', 'ee_read_others_venues', 'ee_read_private_venues')
231
-                ),
232
-                new EE_Meta_Capability_Map_Read(
233
-                    'ee_read_registration',
234
-                    array('Registration', '', 'ee_read_others_registrations', '')
235
-                ),
236
-                new EE_Meta_Capability_Map_Read(
237
-                    'ee_read_checkin',
238
-                    array('Registration', '', 'ee_read_others_checkins', '')
239
-                ),
240
-                new EE_Meta_Capability_Map_Messages_Cap(
241
-                    'ee_read_message',
242
-                    array('Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages')
243
-                ),
244
-                new EE_Meta_Capability_Map_Read(
245
-                    'ee_read_default_ticket',
246
-                    array('Ticket', '', 'ee_read_others_default_tickets', '')
247
-                ),
248
-                new EE_Meta_Capability_Map_Read(
249
-                    'ee_read_payment_method',
250
-                    array('Payment_Method', '', 'ee_read_others_payment_methods', '')
251
-                ),
252
-                //deletes
253
-                new EE_Meta_Capability_Map_Delete(
254
-                    'ee_delete_event',
255
-                    array(
256
-                        'Event',
257
-                        'ee_delete_published_events',
258
-                        'ee_delete_others_events',
259
-                        'ee_delete_private_events',
260
-                    )
261
-                ),
262
-                new EE_Meta_Capability_Map_Delete(
263
-                    'ee_delete_venue',
264
-                    array(
265
-                        'Venue',
266
-                        'ee_delete_published_venues',
267
-                        'ee_delete_others_venues',
268
-                        'ee_delete_private_venues',
269
-                    )
270
-                ),
271
-                new EE_Meta_Capability_Map_Delete(
272
-                    'ee_delete_registration',
273
-                    array('Registration', '', 'ee_delete_others_registrations', '')
274
-                ),
275
-                new EE_Meta_Capability_Map_Delete(
276
-                    'ee_delete_checkin',
277
-                    array('Registration', '', 'ee_delete_others_checkins', '')
278
-                ),
279
-                new EE_Meta_Capability_Map_Messages_Cap(
280
-                    'ee_delete_message',
281
-                    array('Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages')
282
-                ),
283
-                new EE_Meta_Capability_Map_Delete(
284
-                    'ee_delete_default_ticket',
285
-                    array('Ticket', '', 'ee_delete_others_default_tickets', '')
286
-                ),
287
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
288
-                    'ee_delete_question',
289
-                    array('Question', '', '', 'delete_system_questions')
290
-                ),
291
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
292
-                    'ee_delete_question_group',
293
-                    array('Question_Group', '', '', 'delete_system_question_groups')
294
-                ),
295
-                new EE_Meta_Capability_Map_Delete(
296
-                    'ee_delete_payment_method',
297
-                    array('Payment_Method', '', 'ee_delete_others_payment_methods', '')
298
-                ),
299
-            );
300
-        }
301
-        return $default_meta_caps;
302
-    }
303
-
304
-
305
-
306
-    /**
307
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
308
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
309
-     *
310
-     * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
311
-     *
312
-     * @since 4.5.0
313
-     * @see   wp-includes/capabilities.php
314
-     *
315
-     * @param array  $caps    actual users capabilities
316
-     * @param string $cap     initial capability name that is being checked (the "map" key)
317
-     * @param int    $user_id The user id
318
-     * @param array  $args    Adds context to the cap. Typically the object ID.
319
-     * @return array actual users capabilities
320
-     * @throws EE_Error
321
-     */
322
-    public function map_meta_caps($caps, $cap, $user_id, $args)
323
-    {
324
-        if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
325
-            //loop through our _meta_caps array
326
-            foreach ($this->_meta_caps as $meta_map) {
327
-                if (! $meta_map instanceof EE_Meta_Capability_Map) {
328
-                    continue;
329
-                }
330
-                // don't load models if there is no object ID in the args
331
-                if (! empty($args[0])) {
332
-                    $meta_map->ensure_is_model();
333
-                }
334
-                $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
335
-            }
336
-        }
337
-        return $caps;
338
-    }
339
-
340
-
341
-
342
-    /**
343
-     * This sets up and returns the initial capabilities map for Event Espresso
344
-     * Note this array is filtered.
345
-     * It is assumed that all available EE capabilities are assigned to the administrator role.
346
-     *
347
-     * @since 4.5.0
348
-     *
349
-     * @return array
350
-     */
351
-    private function _init_caps_map()
352
-    {
353
-        return apply_filters(
354
-            'FHEE__EE_Capabilities__init_caps_map__caps',
355
-            array(
356
-                'administrator'           => array(
357
-                    //basic access
358
-                    'ee_read_ee',
359
-                    //gateways
360
-                    /**
361
-                     * note that with payment method capabilities, although we've implemented
362
-                     * capability mapping which will be used for accessing payment methods owned by
363
-                     * other users.  This is not fully implemented yet in the payment method ui.
364
-                     * Currently only the "plural" caps are in active use.
365
-                     * (Specific payment method caps are in use as well).
366
-                     **/
367
-                    'ee_manage_gateways',
368
-                    'ee_read_payment_methods',
369
-                    'ee_read_others_payment_methods',
370
-                    'ee_edit_payment_methods',
371
-                    'ee_edit_others_payment_methods',
372
-                    'ee_delete_payment_methods',
373
-                    //events
374
-                    'ee_publish_events',
375
-                    'ee_read_private_events',
376
-                    'ee_read_others_events',
377
-                    'ee_read_events',
378
-                    'ee_edit_events',
379
-                    'ee_edit_published_events',
380
-                    'ee_edit_others_events',
381
-                    'ee_edit_private_events',
382
-                    'ee_delete_published_events',
383
-                    'ee_delete_private_events',
384
-                    'ee_delete_events',
385
-                    'ee_delete_others_events',
386
-                    //event categories
387
-                    'ee_manage_event_categories',
388
-                    'ee_edit_event_category',
389
-                    'ee_delete_event_category',
390
-                    'ee_assign_event_category',
391
-                    //venues
392
-                    'ee_publish_venues',
393
-                    'ee_read_venues',
394
-                    'ee_read_others_venues',
395
-                    'ee_read_private_venues',
396
-                    'ee_edit_venues',
397
-                    'ee_edit_others_venues',
398
-                    'ee_edit_published_venues',
399
-                    'ee_edit_private_venues',
400
-                    'ee_delete_venues',
401
-                    'ee_delete_others_venues',
402
-                    'ee_delete_private_venues',
403
-                    'ee_delete_published_venues',
404
-                    //venue categories
405
-                    'ee_manage_venue_categories',
406
-                    'ee_edit_venue_category',
407
-                    'ee_delete_venue_category',
408
-                    'ee_assign_venue_category',
409
-                    //contacts
410
-                    'ee_read_contacts',
411
-                    'ee_edit_contacts',
412
-                    'ee_delete_contacts',
413
-                    //registrations
414
-                    'ee_read_registrations',
415
-                    'ee_read_others_registrations',
416
-                    'ee_edit_registrations',
417
-                    'ee_edit_others_registrations',
418
-                    'ee_delete_registrations',
419
-                    //checkins
420
-                    'ee_read_others_checkins',
421
-                    'ee_read_checkins',
422
-                    'ee_edit_checkins',
423
-                    'ee_edit_others_checkins',
424
-                    'ee_delete_checkins',
425
-                    'ee_delete_others_checkins',
426
-                    //transactions && payments
427
-                    'ee_read_transaction',
428
-                    'ee_read_transactions',
429
-                    'ee_edit_payments',
430
-                    'ee_delete_payments',
431
-                    //messages
432
-                    'ee_read_messages',
433
-                    'ee_read_others_messages',
434
-                    'ee_read_global_messages',
435
-                    'ee_edit_global_messages',
436
-                    'ee_edit_messages',
437
-                    'ee_edit_others_messages',
438
-                    'ee_delete_messages',
439
-                    'ee_delete_others_messages',
440
-                    'ee_delete_global_messages',
441
-                    'ee_send_message',
442
-                    //tickets
443
-                    'ee_read_default_tickets',
444
-                    'ee_read_others_default_tickets',
445
-                    'ee_edit_default_tickets',
446
-                    'ee_edit_others_default_tickets',
447
-                    'ee_delete_default_tickets',
448
-                    'ee_delete_others_default_tickets',
449
-                    //prices
450
-                    'ee_edit_default_price',
451
-                    'ee_edit_default_prices',
452
-                    'ee_delete_default_price',
453
-                    'ee_delete_default_prices',
454
-                    'ee_edit_default_price_type',
455
-                    'ee_edit_default_price_types',
456
-                    'ee_delete_default_price_type',
457
-                    'ee_delete_default_price_types',
458
-                    'ee_read_default_prices',
459
-                    'ee_read_default_price_types',
460
-                    //registration form
461
-                    'ee_edit_questions',
462
-                    'ee_edit_system_questions',
463
-                    'ee_read_questions',
464
-                    'ee_delete_questions',
465
-                    'ee_edit_question_groups',
466
-                    'ee_read_question_groups',
467
-                    'ee_edit_system_question_groups',
468
-                    'ee_delete_question_groups',
469
-                    //event_type taxonomy
470
-                    'ee_assign_event_type',
471
-                    'ee_manage_event_types',
472
-                    'ee_edit_event_type',
473
-                    'ee_delete_event_type',
474
-                ),
475
-                'ee_events_administrator' => array(
476
-                    //core wp caps
477
-                    'read',
478
-                    'read_private_pages',
479
-                    'read_private_posts',
480
-                    'edit_users',
481
-                    'edit_posts',
482
-                    'edit_pages',
483
-                    'edit_published_posts',
484
-                    'edit_published_pages',
485
-                    'edit_private_pages',
486
-                    'edit_private_posts',
487
-                    'edit_others_posts',
488
-                    'edit_others_pages',
489
-                    'publish_posts',
490
-                    'publish_pages',
491
-                    'delete_posts',
492
-                    'delete_pages',
493
-                    'delete_private_pages',
494
-                    'delete_private_posts',
495
-                    'delete_published_pages',
496
-                    'delete_published_posts',
497
-                    'delete_others_posts',
498
-                    'delete_others_pages',
499
-                    'manage_categories',
500
-                    'manage_links',
501
-                    'moderate_comments',
502
-                    'unfiltered_html',
503
-                    'upload_files',
504
-                    'export',
505
-                    'import',
506
-                    'list_users',
507
-                    'level_1', //required if user with this role shows up in author dropdowns
508
-                    //basic ee access
509
-                    'ee_read_ee',
510
-                    //events
511
-                    'ee_publish_events',
512
-                    'ee_read_private_events',
513
-                    'ee_read_others_events',
514
-                    'ee_read_event',
515
-                    'ee_read_events',
516
-                    'ee_edit_event',
517
-                    'ee_edit_events',
518
-                    'ee_edit_published_events',
519
-                    'ee_edit_others_events',
520
-                    'ee_edit_private_events',
521
-                    'ee_delete_published_events',
522
-                    'ee_delete_private_events',
523
-                    'ee_delete_event',
524
-                    'ee_delete_events',
525
-                    'ee_delete_others_events',
526
-                    //event categories
527
-                    'ee_manage_event_categories',
528
-                    'ee_edit_event_category',
529
-                    'ee_delete_event_category',
530
-                    'ee_assign_event_category',
531
-                    //venues
532
-                    'ee_publish_venues',
533
-                    'ee_read_venue',
534
-                    'ee_read_venues',
535
-                    'ee_read_others_venues',
536
-                    'ee_read_private_venues',
537
-                    'ee_edit_venue',
538
-                    'ee_edit_venues',
539
-                    'ee_edit_others_venues',
540
-                    'ee_edit_published_venues',
541
-                    'ee_edit_private_venues',
542
-                    'ee_delete_venue',
543
-                    'ee_delete_venues',
544
-                    'ee_delete_others_venues',
545
-                    'ee_delete_private_venues',
546
-                    'ee_delete_published_venues',
547
-                    //venue categories
548
-                    'ee_manage_venue_categories',
549
-                    'ee_edit_venue_category',
550
-                    'ee_delete_venue_category',
551
-                    'ee_assign_venue_category',
552
-                    //contacts
553
-                    'ee_read_contacts',
554
-                    'ee_edit_contacts',
555
-                    'ee_delete_contacts',
556
-                    //registrations
557
-                    'ee_read_registrations',
558
-                    'ee_read_others_registrations',
559
-                    'ee_edit_registration',
560
-                    'ee_edit_registrations',
561
-                    'ee_edit_others_registrations',
562
-                    'ee_delete_registration',
563
-                    'ee_delete_registrations',
564
-                    //checkins
565
-                    'ee_read_others_checkins',
566
-                    'ee_read_checkins',
567
-                    'ee_edit_checkins',
568
-                    'ee_edit_others_checkins',
569
-                    'ee_delete_checkins',
570
-                    'ee_delete_others_checkins',
571
-                    //transactions && payments
572
-                    'ee_read_transaction',
573
-                    'ee_read_transactions',
574
-                    'ee_edit_payments',
575
-                    'ee_delete_payments',
576
-                    //messages
577
-                    'ee_read_messages',
578
-                    'ee_read_others_messages',
579
-                    'ee_read_global_messages',
580
-                    'ee_edit_global_messages',
581
-                    'ee_edit_messages',
582
-                    'ee_edit_others_messages',
583
-                    'ee_delete_messages',
584
-                    'ee_delete_others_messages',
585
-                    'ee_delete_global_messages',
586
-                    'ee_send_message',
587
-                    //tickets
588
-                    'ee_read_default_tickets',
589
-                    'ee_read_others_default_tickets',
590
-                    'ee_edit_default_tickets',
591
-                    'ee_edit_others_default_tickets',
592
-                    'ee_delete_default_tickets',
593
-                    'ee_delete_others_default_tickets',
594
-                    //prices
595
-                    'ee_edit_default_price',
596
-                    'ee_edit_default_prices',
597
-                    'ee_delete_default_price',
598
-                    'ee_delete_default_prices',
599
-                    'ee_edit_default_price_type',
600
-                    'ee_edit_default_price_types',
601
-                    'ee_delete_default_price_type',
602
-                    'ee_delete_default_price_types',
603
-                    'ee_read_default_prices',
604
-                    'ee_read_default_price_types',
605
-                    //registration form
606
-                    'ee_edit_questions',
607
-                    'ee_edit_system_questions',
608
-                    'ee_read_questions',
609
-                    'ee_delete_questions',
610
-                    'ee_edit_question_groups',
611
-                    'ee_read_question_groups',
612
-                    'ee_edit_system_question_groups',
613
-                    'ee_delete_question_groups',
614
-                    //event_type taxonomy
615
-                    'ee_assign_event_type',
616
-                    'ee_manage_event_types',
617
-                    'ee_edit_event_type',
618
-                    'ee_delete_event_type',
619
-                )
620
-            )
621
-        );
622
-    }
623
-
624
-
625
-
626
-    /**
627
-     * @return bool
628
-     * @throws EE_Error
629
-     */
630
-    private function setupCapabilitiesMap()
631
-    {
632
-        // if the initialization process hasn't even started, then we need to call init_caps()
633
-        if($this->initialized === null) {
634
-            return $this->init_caps();
635
-        }
636
-        // unless resetting, get caps from db if we haven't already
637
-        $this->capabilities_map = $this->reset || ! empty($this->capabilities_map)
638
-            ? $this->capabilities_map
639
-            : get_option(self::option_name, array());
640
-        return true;
641
-    }
642
-
643
-
644
-
645
-    /**
646
-     * @param bool $update
647
-     * @return bool
648
-     */
649
-    private function updateCapabilitiesMap($update = true)
650
-    {
651
-        return $update ? update_option(self::option_name, $this->capabilities_map) : false;
652
-    }
653
-
654
-
655
-
656
-    /**
657
-     * Adds capabilities to roles.
658
-     *
659
-     * @since 4.9.42
660
-     * @param array $capabilities_to_add array of capabilities to add, indexed by roles.
661
-     *                                   Note that this should ONLY be called on activation hook
662
-     *                                   otherwise the caps will be added on every request.
663
-     * @return bool
664
-     * @throws \EE_Error
665
-     */
666
-    public function addCaps(array $capabilities_to_add)
667
-    {
668
-        // don't do anything if the capabilities map can not be initialized
669
-        if (! $this->setupCapabilitiesMap()) {
670
-            return false;
671
-        }
672
-        // and filter the array so others can get in on the fun during resets
673
-        $capabilities_to_add = apply_filters(
674
-            'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
675
-            $capabilities_to_add,
676
-            $this->reset,
677
-            $this->capabilities_map
678
-        );
679
-        $update_capabilities_map = false;
680
-        // if not reset, see what caps are new for each role. if they're new, add them.
681
-        foreach ($capabilities_to_add as $role => $caps_for_role) {
682
-            if (is_array($caps_for_role)) {
683
-                foreach ($caps_for_role as $cap) {
684
-                    if (
685
-                        ! $this->capHasBeenAddedToRole($role, $cap)
686
-                        && $this->add_cap_to_role($role, $cap, true, false)
687
-                    ) {
688
-                        $update_capabilities_map = true;
689
-                    }
690
-                }
691
-            }
692
-        }
693
-        // now let's just save the cap that has been set but only if there's been a change.
694
-        $updated = $this->updateCapabilitiesMap($update_capabilities_map);
695
-        do_action('AHEE__EE_Capabilities__addCaps__complete', $this->capabilities_map, $updated);
696
-        return $updated;
697
-    }
698
-
699
-
700
-
701
-    /**
702
-     * Loops through the capabilities map and removes the role caps specified by the incoming array
703
-     *
704
-     * @param array $caps_map map of capabilities to be removed (indexed by roles)
705
-     * @return bool
706
-     * @throws \EE_Error
707
-     */
708
-    public function removeCaps($caps_map)
709
-    {
710
-        // don't do anything if the capabilities map can not be initialized
711
-        if (! $this->setupCapabilitiesMap()) {
712
-            return false;
713
-        }
714
-        $update_capabilities_map = false;
715
-        foreach ($caps_map as $role => $caps_for_role) {
716
-            if (is_array($caps_for_role)) {
717
-                foreach ($caps_for_role as $cap) {
718
-                    if (
719
-                        $this->capHasBeenAddedToRole($role, $cap)
720
-                        && $this->remove_cap_from_role($role, $cap, false)
721
-                    ) {
722
-                        $update_capabilities_map = true;
723
-                    }
724
-                }
725
-            }
726
-        }
727
-        // maybe resave the caps
728
-        return $this->updateCapabilitiesMap($update_capabilities_map);
729
-    }
730
-
731
-
732
-
733
-    /**
734
-     * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
735
-     * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
736
-     * this is a wrapper for $wp_role->add_cap()
737
-     *
738
-     * @see   wp-includes/capabilities.php
739
-     * @since 4.5.0
740
-     * @param string|WP_Role $role  A WordPress role the capability is being added to
741
-     * @param string         $cap   The capability being added to the role
742
-     * @param bool           $grant Whether to grant access to this cap on this role.
743
-     * @param bool           $update_capabilities_map
744
-     * @return bool
745
-     * @throws \EE_Error
746
-     */
747
-    public function add_cap_to_role($role, $cap, $grant = true, $update_capabilities_map = true)
748
-    {
749
-        // capture incoming value for $role because we may need it to create a new WP_Role
750
-        $orig_role = $role;
751
-        $role = $role instanceof WP_Role ? $role : get_role($role);
752
-        //if the role isn't available then we create it.
753
-        if (! $role instanceof WP_Role) {
754
-            // if a plugin wants to create a specific role name then they should create the role before
755
-            // EE_Capabilities does.  Otherwise this function will create the role name from the slug:
756
-            // - removes any `ee_` namespacing from the start of the slug.
757
-            // - replaces `_` with ` ` (empty space).
758
-            // - sentence case on the resulting string.
759
-            $role_label = ucwords(str_replace(array('ee_', '_'), array('', ' '), $orig_role));
760
-            $role = add_role($orig_role, $role_label);
761
-        }
762
-        if ($role instanceof WP_Role) {
763
-            // don't do anything if the capabilities map can not be initialized
764
-            if (! $this->setupCapabilitiesMap()) {
765
-                return false;
766
-            }
767
-            if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
768
-                $role->add_cap($cap, $grant);
769
-                $this->capabilities_map[ $role->name ][] = $cap;
770
-                $this->updateCapabilitiesMap($update_capabilities_map);
771
-                return true;
772
-            }
773
-        }
774
-        return false;
775
-    }
776
-
777
-
778
-
779
-    /**
780
-     * Functions similarly to add_cap_to_role except removes cap from given role.
781
-     * Wrapper for $wp_role->remove_cap()
782
-     *
783
-     * @see   wp-includes/capabilities.php
784
-     * @since 4.5.0
785
-     * @param string|WP_Role $role A WordPress role the capability is being removed from.
786
-     * @param string         $cap  The capability being removed
787
-     * @param bool           $update_capabilities_map
788
-     * @return bool
789
-     * @throws \EE_Error
790
-     */
791
-    public function remove_cap_from_role($role, $cap, $update_capabilities_map = true)
792
-    {
793
-        // don't do anything if the capabilities map can not be initialized
794
-        if (! $this->setupCapabilitiesMap()) {
795
-            return false;
796
-        }
797
-        $role = $role instanceof WP_Role ? $role :get_role($role);
798
-        if ($index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
799
-            $role->remove_cap($cap);
800
-            unset($this->capabilities_map[ $role->name ][ $index ]);
801
-            $this->updateCapabilitiesMap($update_capabilities_map);
802
-            return true;
803
-        }
804
-        return false;
805
-    }
806
-
807
-
808
-
809
-    /**
810
-     * @param string $role_name
811
-     * @param string $cap
812
-     * @param bool   $get_index
813
-     * @return bool|mixed
814
-     */
815
-    private function capHasBeenAddedToRole($role_name='', $cap='', $get_index = false)
816
-    {
817
-        if (
818
-            isset($this->capabilities_map[$role_name])
819
-            && ($index = array_search($cap, $this->capabilities_map[$role_name], true)) !== false
820
-        ) {
821
-            return $get_index ? $index : true;
822
-        }
823
-        return false;
824
-    }
825
-
826
-
827
-
828
-    /**
829
-     * Wrapper for the native WP current_user_can() method.
830
-     * This is provided as a handy method for a couple things:
831
-     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
832
-     * write those filters wherever current_user_can is called).
833
-     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
834
-     *
835
-     * @since 4.5.0
836
-     *
837
-     * @param string $cap     The cap being checked.
838
-     * @param string $context The context where the current_user_can is being called from.
839
-     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
840
-     *                        filters.
841
-     *
842
-     * @return bool  Whether user can or not.
843
-     */
844
-    public function current_user_can($cap, $context, $id = 0)
845
-    {
846
-        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
847
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id);
848
-        $filtered_cap = apply_filters(
849
-            'FHEE__EE_Capabilities__current_user_can__cap',
850
-            $filtered_cap,
851
-            $context,
852
-            $cap,
853
-            $id
854
-        );
855
-        return ! empty($id)
856
-            ? current_user_can($filtered_cap, $id)
857
-            : current_user_can($filtered_cap);
858
-    }
859
-
860
-
861
-
862
-    /**
863
-     * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
864
-     *
865
-     * @param int|WP_User $user    Either the user_id or a WP_User object
866
-     * @param string      $cap     The capability string being checked
867
-     * @param string      $context The context where the user_can is being called from (used in filters).
868
-     * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
869
-     *                             filters)
870
-     *
871
-     * @return bool Whether user can or not.
872
-     */
873
-    public function user_can($user, $cap, $context, $id = 0)
874
-    {
875
-        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
876
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
877
-        $filtered_cap = apply_filters(
878
-            'FHEE__EE_Capabilities__user_can__cap',
879
-            $filtered_cap,
880
-            $context,
881
-            $cap,
882
-            $user,
883
-            $id
884
-        );
885
-        return ! empty($id)
886
-            ? user_can($user, $filtered_cap, $id)
887
-            : user_can($user, $filtered_cap);
888
-    }
889
-
890
-
891
-
892
-    /**
893
-     * Wrapper for the native WP current_user_can_for_blog() method.
894
-     * This is provided as a handy method for a couple things:
895
-     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
896
-     * write those filters wherever current_user_can is called).
897
-     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
898
-     *
899
-     * @since 4.5.0
900
-     *
901
-     * @param int    $blog_id The blog id that is being checked for.
902
-     * @param string $cap     The cap being checked.
903
-     * @param string $context The context where the current_user_can is being called from.
904
-     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
905
-     *                        filters.
906
-     *
907
-     * @return bool  Whether user can or not.
908
-     */
909
-    public function current_user_can_for_blog($blog_id, $cap, $context, $id = 0)
910
-    {
911
-        $user_can = ! empty($id)
912
-            ? current_user_can_for_blog($blog_id, $cap, $id)
913
-            : current_user_can($blog_id, $cap);
914
-        //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
915
-        $user_can = apply_filters(
916
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
917
-            $user_can,
918
-            $blog_id,
919
-            $cap,
920
-            $id
921
-        );
922
-        $user_can = apply_filters(
923
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
924
-            $user_can,
925
-            $context,
926
-            $blog_id,
927
-            $cap,
928
-            $id
929
-        );
930
-        return $user_can;
931
-    }
932
-
933
-
934
-
935
-    /**
936
-     * This helper method just returns an array of registered EE capabilities.
937
-     *
938
-     * @since 4.5.0
939
-     * @param string $role If empty then the entire role/capability map is returned.
940
-     *                     Otherwise just the capabilities for the given role are returned.
941
-     * @return array
942
-     * @throws EE_Error
943
-     */
944
-    public function get_ee_capabilities($role = 'administrator')
945
-    {
946
-        if (! $this->initialized) {
947
-            $this->init_caps();
948
-        }
949
-        if (empty($role)) {
950
-            return $this->capabilities_map;
951
-        }
952
-        return isset($this->capabilities_map[ $role ])
953
-            ? $this->capabilities_map[ $role ]
954
-            : array();
955
-    }
956
-
957
-
958
-
959
-    /**
960
-     * @deprecated 4.9.42
961
-     * @param bool  $reset      If you need to reset Event Espresso's capabilities,
962
-     *                          then please use the init_caps() method with the "$reset" parameter set to "true"
963
-     * @param array $caps_map   Optional.
964
-     *                          Can be used to send a custom map of roles and capabilities for setting them up.
965
-     *                          Note that this should ONLY be called on activation hook or some other one-time
966
-     *                          task otherwise the caps will be added on every request.
967
-     * @return void
968
-     * @throws EE_Error
969
-     */
970
-    public function init_role_caps($reset = false, $caps_map = array())
971
-    {
972
-        // If this method is called directly and reset is set as 'true',
973
-        // then display a doing it wrong notice, because we want resets to go through init_caps()
974
-        // to guarantee that everything is set up correctly.
975
-        // This prevents the capabilities map getting reset incorrectly by direct calls to this method.
976
-        if ($reset) {
977
-            EE_Error::doing_it_wrong(
978
-                __METHOD__,
979
-                sprintf(
980
-                    esc_html__(
981
-                        'The "%1$s" parameter for the "%2$s" method is deprecated. If you need to reset Event Espresso\'s capabilities, then please use the "%3$s" method with the "%1$s" parameter set to "%4$s".',
982
-                        'event_espresso'
983
-                    ),
984
-                    '$reset',
985
-                    __METHOD__ . '()',
986
-                    'EE_Capabilities::init_caps()',
987
-                    'true'
988
-                ),
989
-                '4.9.42',
990
-                '5.0.0'
991
-            );
992
-        }
993
-        $this->addCaps($caps_map);
994
-    }
21
+	/**
22
+	 * the name of the wp option used to store caps previously initialized
23
+	 */
24
+	const option_name = 'ee_caps_initialized';
25
+
26
+	/**
27
+	 * instance of EE_Capabilities object
28
+	 *
29
+	 * @var EE_Capabilities
30
+	 */
31
+	private static $_instance;
32
+
33
+
34
+	/**
35
+	 * This is a map of caps that correspond to a default WP_Role.
36
+	 * Array is indexed by Role and values are ee capabilities.
37
+	 *
38
+	 * @since 4.5.0
39
+	 *
40
+	 * @var array
41
+	 */
42
+	private $capabilities_map = array();
43
+
44
+	/**
45
+	 * This used to hold an array of EE_Meta_Capability_Map objects
46
+	 * that define the granular capabilities mapped to for a user depending on context.
47
+	 *
48
+	 * @var EE_Meta_Capability_Map[]
49
+	 */
50
+	private $_meta_caps = array();
51
+
52
+	/**
53
+	 * The internal $capabilities_map needs to be initialized before it can be used.
54
+	 * This flag tracks whether that has happened or not.
55
+	 * But for this to work, we need three states to indicate:
56
+	 *      initialization has not occurred at all
57
+	 *      initialization has started but is not complete
58
+	 *      initialization is complete
59
+	 * The reason this is needed is because the addCaps() method
60
+	 * normally requires the $capabilities_map to be initialized,
61
+	 * but is also used during the initialization process.
62
+	 * So:
63
+	 *      If initialized === null, init_caps() will be called before any other methods will run.
64
+	 *      If initialized === false, then init_caps() is in the process of running it's logic.
65
+	 *      If initialized === true, then init_caps() has completed the initialization process.
66
+	 *
67
+	 * @var boolean|null $initialized
68
+	 */
69
+	private $initialized;
70
+
71
+	/**
72
+	 * @var boolean $reset
73
+	 */
74
+	private $reset = false;
75
+
76
+
77
+
78
+	/**
79
+	 * singleton method used to instantiate class object
80
+	 *
81
+	 * @since 4.5.0
82
+	 *
83
+	 * @return EE_Capabilities
84
+	 */
85
+	public static function instance()
86
+	{
87
+		//check if instantiated, and if not do so.
88
+		if (! self::$_instance instanceof EE_Capabilities) {
89
+			self::$_instance = new self();
90
+		}
91
+		return self::$_instance;
92
+	}
93
+
94
+
95
+
96
+	/**
97
+	 * private constructor
98
+	 *
99
+	 * @since 4.5.0
100
+	 */
101
+	private function __construct()
102
+	{
103
+	}
104
+
105
+
106
+
107
+	/**
108
+	 * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
109
+	 *
110
+	 * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
111
+	 *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
112
+	 *                    ensures that they are up to date.
113
+	 *
114
+	 * @since 4.5.0
115
+	 * @return bool
116
+	 * @throws EE_Error
117
+	 */
118
+	public function init_caps($reset = false)
119
+	{
120
+		if(! EE_Maintenance_Mode::instance()->models_can_query()){
121
+			return false;
122
+		}
123
+		$this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
124
+		// if reset, then completely delete the cache option and clear the $capabilities_map property.
125
+		if ($this->reset) {
126
+			$this->initialized = null;
127
+			$this->capabilities_map = array();
128
+			delete_option(self::option_name);
129
+		}
130
+		if ($this->initialized === null) {
131
+			$this->initialized = false;
132
+			do_action(
133
+				'AHEE__EE_Capabilities__init_caps__before_initialization',
134
+				$this->reset
135
+			);
136
+			$this->addCaps($this->_init_caps_map());
137
+			$this->_set_meta_caps();
138
+			do_action(
139
+				'AHEE__EE_Capabilities__init_caps__after_initialization',
140
+				$this->capabilities_map
141
+			);
142
+			$this->initialized = true;
143
+		}
144
+		// reset $this->reset so that it's not stuck on true if init_caps() gets called again
145
+		$this->reset = false;
146
+		return true;
147
+	}
148
+
149
+
150
+
151
+	/**
152
+	 * This sets the meta caps property.
153
+	 *
154
+	 * @since 4.5.0
155
+	 * @return void
156
+	 * @throws EE_Error
157
+	 */
158
+	private function _set_meta_caps()
159
+	{
160
+		// get default meta caps and filter the returned array
161
+		$this->_meta_caps = apply_filters(
162
+			'FHEE__EE_Capabilities___set_meta_caps__meta_caps',
163
+			$this->_get_default_meta_caps_array()
164
+		);
165
+		//add filter for map_meta_caps but only if models can query.
166
+		if (! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
167
+			add_filter('map_meta_cap', array($this, 'map_meta_caps'), 10, 4);
168
+		}
169
+	}
170
+
171
+
172
+
173
+	/**
174
+	 * This builds and returns the default meta_caps array only once.
175
+	 *
176
+	 * @since  4.8.28.rc.012
177
+	 * @return array
178
+	 * @throws EE_Error
179
+	 */
180
+	private function _get_default_meta_caps_array()
181
+	{
182
+		static $default_meta_caps = array();
183
+		// make sure we're only ever initializing the default _meta_caps array once if it's empty.
184
+		if (empty($default_meta_caps)) {
185
+			$default_meta_caps = array(
186
+				//edits
187
+				new EE_Meta_Capability_Map_Edit(
188
+					'ee_edit_event',
189
+					array('Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events')
190
+				),
191
+				new EE_Meta_Capability_Map_Edit(
192
+					'ee_edit_venue',
193
+					array('Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues')
194
+				),
195
+				new EE_Meta_Capability_Map_Edit(
196
+					'ee_edit_registration',
197
+					array('Registration', '', 'ee_edit_others_registrations', '')
198
+				),
199
+				new EE_Meta_Capability_Map_Edit(
200
+					'ee_edit_checkin',
201
+					array('Registration', '', 'ee_edit_others_checkins', '')
202
+				),
203
+				new EE_Meta_Capability_Map_Messages_Cap(
204
+					'ee_edit_message',
205
+					array('Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages')
206
+				),
207
+				new EE_Meta_Capability_Map_Edit(
208
+					'ee_edit_default_ticket',
209
+					array('Ticket', '', 'ee_edit_others_default_tickets', '')
210
+				),
211
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
212
+					'ee_edit_question',
213
+					array('Question', '', '', 'ee_edit_system_questions')
214
+				),
215
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
216
+					'ee_edit_question_group',
217
+					array('Question_Group', '', '', 'ee_edit_system_question_groups')
218
+				),
219
+				new EE_Meta_Capability_Map_Edit(
220
+					'ee_edit_payment_method',
221
+					array('Payment_Method', '', 'ee_edit_others_payment_methods', '')
222
+				),
223
+				//reads
224
+				new EE_Meta_Capability_Map_Read(
225
+					'ee_read_event',
226
+					array('Event', '', 'ee_read_others_events', 'ee_read_private_events')
227
+				),
228
+				new EE_Meta_Capability_Map_Read(
229
+					'ee_read_venue',
230
+					array('Venue', '', 'ee_read_others_venues', 'ee_read_private_venues')
231
+				),
232
+				new EE_Meta_Capability_Map_Read(
233
+					'ee_read_registration',
234
+					array('Registration', '', 'ee_read_others_registrations', '')
235
+				),
236
+				new EE_Meta_Capability_Map_Read(
237
+					'ee_read_checkin',
238
+					array('Registration', '', 'ee_read_others_checkins', '')
239
+				),
240
+				new EE_Meta_Capability_Map_Messages_Cap(
241
+					'ee_read_message',
242
+					array('Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages')
243
+				),
244
+				new EE_Meta_Capability_Map_Read(
245
+					'ee_read_default_ticket',
246
+					array('Ticket', '', 'ee_read_others_default_tickets', '')
247
+				),
248
+				new EE_Meta_Capability_Map_Read(
249
+					'ee_read_payment_method',
250
+					array('Payment_Method', '', 'ee_read_others_payment_methods', '')
251
+				),
252
+				//deletes
253
+				new EE_Meta_Capability_Map_Delete(
254
+					'ee_delete_event',
255
+					array(
256
+						'Event',
257
+						'ee_delete_published_events',
258
+						'ee_delete_others_events',
259
+						'ee_delete_private_events',
260
+					)
261
+				),
262
+				new EE_Meta_Capability_Map_Delete(
263
+					'ee_delete_venue',
264
+					array(
265
+						'Venue',
266
+						'ee_delete_published_venues',
267
+						'ee_delete_others_venues',
268
+						'ee_delete_private_venues',
269
+					)
270
+				),
271
+				new EE_Meta_Capability_Map_Delete(
272
+					'ee_delete_registration',
273
+					array('Registration', '', 'ee_delete_others_registrations', '')
274
+				),
275
+				new EE_Meta_Capability_Map_Delete(
276
+					'ee_delete_checkin',
277
+					array('Registration', '', 'ee_delete_others_checkins', '')
278
+				),
279
+				new EE_Meta_Capability_Map_Messages_Cap(
280
+					'ee_delete_message',
281
+					array('Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages')
282
+				),
283
+				new EE_Meta_Capability_Map_Delete(
284
+					'ee_delete_default_ticket',
285
+					array('Ticket', '', 'ee_delete_others_default_tickets', '')
286
+				),
287
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
288
+					'ee_delete_question',
289
+					array('Question', '', '', 'delete_system_questions')
290
+				),
291
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
292
+					'ee_delete_question_group',
293
+					array('Question_Group', '', '', 'delete_system_question_groups')
294
+				),
295
+				new EE_Meta_Capability_Map_Delete(
296
+					'ee_delete_payment_method',
297
+					array('Payment_Method', '', 'ee_delete_others_payment_methods', '')
298
+				),
299
+			);
300
+		}
301
+		return $default_meta_caps;
302
+	}
303
+
304
+
305
+
306
+	/**
307
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
308
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
309
+	 *
310
+	 * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
311
+	 *
312
+	 * @since 4.5.0
313
+	 * @see   wp-includes/capabilities.php
314
+	 *
315
+	 * @param array  $caps    actual users capabilities
316
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
317
+	 * @param int    $user_id The user id
318
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
319
+	 * @return array actual users capabilities
320
+	 * @throws EE_Error
321
+	 */
322
+	public function map_meta_caps($caps, $cap, $user_id, $args)
323
+	{
324
+		if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
325
+			//loop through our _meta_caps array
326
+			foreach ($this->_meta_caps as $meta_map) {
327
+				if (! $meta_map instanceof EE_Meta_Capability_Map) {
328
+					continue;
329
+				}
330
+				// don't load models if there is no object ID in the args
331
+				if (! empty($args[0])) {
332
+					$meta_map->ensure_is_model();
333
+				}
334
+				$caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
335
+			}
336
+		}
337
+		return $caps;
338
+	}
339
+
340
+
341
+
342
+	/**
343
+	 * This sets up and returns the initial capabilities map for Event Espresso
344
+	 * Note this array is filtered.
345
+	 * It is assumed that all available EE capabilities are assigned to the administrator role.
346
+	 *
347
+	 * @since 4.5.0
348
+	 *
349
+	 * @return array
350
+	 */
351
+	private function _init_caps_map()
352
+	{
353
+		return apply_filters(
354
+			'FHEE__EE_Capabilities__init_caps_map__caps',
355
+			array(
356
+				'administrator'           => array(
357
+					//basic access
358
+					'ee_read_ee',
359
+					//gateways
360
+					/**
361
+					 * note that with payment method capabilities, although we've implemented
362
+					 * capability mapping which will be used for accessing payment methods owned by
363
+					 * other users.  This is not fully implemented yet in the payment method ui.
364
+					 * Currently only the "plural" caps are in active use.
365
+					 * (Specific payment method caps are in use as well).
366
+					 **/
367
+					'ee_manage_gateways',
368
+					'ee_read_payment_methods',
369
+					'ee_read_others_payment_methods',
370
+					'ee_edit_payment_methods',
371
+					'ee_edit_others_payment_methods',
372
+					'ee_delete_payment_methods',
373
+					//events
374
+					'ee_publish_events',
375
+					'ee_read_private_events',
376
+					'ee_read_others_events',
377
+					'ee_read_events',
378
+					'ee_edit_events',
379
+					'ee_edit_published_events',
380
+					'ee_edit_others_events',
381
+					'ee_edit_private_events',
382
+					'ee_delete_published_events',
383
+					'ee_delete_private_events',
384
+					'ee_delete_events',
385
+					'ee_delete_others_events',
386
+					//event categories
387
+					'ee_manage_event_categories',
388
+					'ee_edit_event_category',
389
+					'ee_delete_event_category',
390
+					'ee_assign_event_category',
391
+					//venues
392
+					'ee_publish_venues',
393
+					'ee_read_venues',
394
+					'ee_read_others_venues',
395
+					'ee_read_private_venues',
396
+					'ee_edit_venues',
397
+					'ee_edit_others_venues',
398
+					'ee_edit_published_venues',
399
+					'ee_edit_private_venues',
400
+					'ee_delete_venues',
401
+					'ee_delete_others_venues',
402
+					'ee_delete_private_venues',
403
+					'ee_delete_published_venues',
404
+					//venue categories
405
+					'ee_manage_venue_categories',
406
+					'ee_edit_venue_category',
407
+					'ee_delete_venue_category',
408
+					'ee_assign_venue_category',
409
+					//contacts
410
+					'ee_read_contacts',
411
+					'ee_edit_contacts',
412
+					'ee_delete_contacts',
413
+					//registrations
414
+					'ee_read_registrations',
415
+					'ee_read_others_registrations',
416
+					'ee_edit_registrations',
417
+					'ee_edit_others_registrations',
418
+					'ee_delete_registrations',
419
+					//checkins
420
+					'ee_read_others_checkins',
421
+					'ee_read_checkins',
422
+					'ee_edit_checkins',
423
+					'ee_edit_others_checkins',
424
+					'ee_delete_checkins',
425
+					'ee_delete_others_checkins',
426
+					//transactions && payments
427
+					'ee_read_transaction',
428
+					'ee_read_transactions',
429
+					'ee_edit_payments',
430
+					'ee_delete_payments',
431
+					//messages
432
+					'ee_read_messages',
433
+					'ee_read_others_messages',
434
+					'ee_read_global_messages',
435
+					'ee_edit_global_messages',
436
+					'ee_edit_messages',
437
+					'ee_edit_others_messages',
438
+					'ee_delete_messages',
439
+					'ee_delete_others_messages',
440
+					'ee_delete_global_messages',
441
+					'ee_send_message',
442
+					//tickets
443
+					'ee_read_default_tickets',
444
+					'ee_read_others_default_tickets',
445
+					'ee_edit_default_tickets',
446
+					'ee_edit_others_default_tickets',
447
+					'ee_delete_default_tickets',
448
+					'ee_delete_others_default_tickets',
449
+					//prices
450
+					'ee_edit_default_price',
451
+					'ee_edit_default_prices',
452
+					'ee_delete_default_price',
453
+					'ee_delete_default_prices',
454
+					'ee_edit_default_price_type',
455
+					'ee_edit_default_price_types',
456
+					'ee_delete_default_price_type',
457
+					'ee_delete_default_price_types',
458
+					'ee_read_default_prices',
459
+					'ee_read_default_price_types',
460
+					//registration form
461
+					'ee_edit_questions',
462
+					'ee_edit_system_questions',
463
+					'ee_read_questions',
464
+					'ee_delete_questions',
465
+					'ee_edit_question_groups',
466
+					'ee_read_question_groups',
467
+					'ee_edit_system_question_groups',
468
+					'ee_delete_question_groups',
469
+					//event_type taxonomy
470
+					'ee_assign_event_type',
471
+					'ee_manage_event_types',
472
+					'ee_edit_event_type',
473
+					'ee_delete_event_type',
474
+				),
475
+				'ee_events_administrator' => array(
476
+					//core wp caps
477
+					'read',
478
+					'read_private_pages',
479
+					'read_private_posts',
480
+					'edit_users',
481
+					'edit_posts',
482
+					'edit_pages',
483
+					'edit_published_posts',
484
+					'edit_published_pages',
485
+					'edit_private_pages',
486
+					'edit_private_posts',
487
+					'edit_others_posts',
488
+					'edit_others_pages',
489
+					'publish_posts',
490
+					'publish_pages',
491
+					'delete_posts',
492
+					'delete_pages',
493
+					'delete_private_pages',
494
+					'delete_private_posts',
495
+					'delete_published_pages',
496
+					'delete_published_posts',
497
+					'delete_others_posts',
498
+					'delete_others_pages',
499
+					'manage_categories',
500
+					'manage_links',
501
+					'moderate_comments',
502
+					'unfiltered_html',
503
+					'upload_files',
504
+					'export',
505
+					'import',
506
+					'list_users',
507
+					'level_1', //required if user with this role shows up in author dropdowns
508
+					//basic ee access
509
+					'ee_read_ee',
510
+					//events
511
+					'ee_publish_events',
512
+					'ee_read_private_events',
513
+					'ee_read_others_events',
514
+					'ee_read_event',
515
+					'ee_read_events',
516
+					'ee_edit_event',
517
+					'ee_edit_events',
518
+					'ee_edit_published_events',
519
+					'ee_edit_others_events',
520
+					'ee_edit_private_events',
521
+					'ee_delete_published_events',
522
+					'ee_delete_private_events',
523
+					'ee_delete_event',
524
+					'ee_delete_events',
525
+					'ee_delete_others_events',
526
+					//event categories
527
+					'ee_manage_event_categories',
528
+					'ee_edit_event_category',
529
+					'ee_delete_event_category',
530
+					'ee_assign_event_category',
531
+					//venues
532
+					'ee_publish_venues',
533
+					'ee_read_venue',
534
+					'ee_read_venues',
535
+					'ee_read_others_venues',
536
+					'ee_read_private_venues',
537
+					'ee_edit_venue',
538
+					'ee_edit_venues',
539
+					'ee_edit_others_venues',
540
+					'ee_edit_published_venues',
541
+					'ee_edit_private_venues',
542
+					'ee_delete_venue',
543
+					'ee_delete_venues',
544
+					'ee_delete_others_venues',
545
+					'ee_delete_private_venues',
546
+					'ee_delete_published_venues',
547
+					//venue categories
548
+					'ee_manage_venue_categories',
549
+					'ee_edit_venue_category',
550
+					'ee_delete_venue_category',
551
+					'ee_assign_venue_category',
552
+					//contacts
553
+					'ee_read_contacts',
554
+					'ee_edit_contacts',
555
+					'ee_delete_contacts',
556
+					//registrations
557
+					'ee_read_registrations',
558
+					'ee_read_others_registrations',
559
+					'ee_edit_registration',
560
+					'ee_edit_registrations',
561
+					'ee_edit_others_registrations',
562
+					'ee_delete_registration',
563
+					'ee_delete_registrations',
564
+					//checkins
565
+					'ee_read_others_checkins',
566
+					'ee_read_checkins',
567
+					'ee_edit_checkins',
568
+					'ee_edit_others_checkins',
569
+					'ee_delete_checkins',
570
+					'ee_delete_others_checkins',
571
+					//transactions && payments
572
+					'ee_read_transaction',
573
+					'ee_read_transactions',
574
+					'ee_edit_payments',
575
+					'ee_delete_payments',
576
+					//messages
577
+					'ee_read_messages',
578
+					'ee_read_others_messages',
579
+					'ee_read_global_messages',
580
+					'ee_edit_global_messages',
581
+					'ee_edit_messages',
582
+					'ee_edit_others_messages',
583
+					'ee_delete_messages',
584
+					'ee_delete_others_messages',
585
+					'ee_delete_global_messages',
586
+					'ee_send_message',
587
+					//tickets
588
+					'ee_read_default_tickets',
589
+					'ee_read_others_default_tickets',
590
+					'ee_edit_default_tickets',
591
+					'ee_edit_others_default_tickets',
592
+					'ee_delete_default_tickets',
593
+					'ee_delete_others_default_tickets',
594
+					//prices
595
+					'ee_edit_default_price',
596
+					'ee_edit_default_prices',
597
+					'ee_delete_default_price',
598
+					'ee_delete_default_prices',
599
+					'ee_edit_default_price_type',
600
+					'ee_edit_default_price_types',
601
+					'ee_delete_default_price_type',
602
+					'ee_delete_default_price_types',
603
+					'ee_read_default_prices',
604
+					'ee_read_default_price_types',
605
+					//registration form
606
+					'ee_edit_questions',
607
+					'ee_edit_system_questions',
608
+					'ee_read_questions',
609
+					'ee_delete_questions',
610
+					'ee_edit_question_groups',
611
+					'ee_read_question_groups',
612
+					'ee_edit_system_question_groups',
613
+					'ee_delete_question_groups',
614
+					//event_type taxonomy
615
+					'ee_assign_event_type',
616
+					'ee_manage_event_types',
617
+					'ee_edit_event_type',
618
+					'ee_delete_event_type',
619
+				)
620
+			)
621
+		);
622
+	}
623
+
624
+
625
+
626
+	/**
627
+	 * @return bool
628
+	 * @throws EE_Error
629
+	 */
630
+	private function setupCapabilitiesMap()
631
+	{
632
+		// if the initialization process hasn't even started, then we need to call init_caps()
633
+		if($this->initialized === null) {
634
+			return $this->init_caps();
635
+		}
636
+		// unless resetting, get caps from db if we haven't already
637
+		$this->capabilities_map = $this->reset || ! empty($this->capabilities_map)
638
+			? $this->capabilities_map
639
+			: get_option(self::option_name, array());
640
+		return true;
641
+	}
642
+
643
+
644
+
645
+	/**
646
+	 * @param bool $update
647
+	 * @return bool
648
+	 */
649
+	private function updateCapabilitiesMap($update = true)
650
+	{
651
+		return $update ? update_option(self::option_name, $this->capabilities_map) : false;
652
+	}
653
+
654
+
655
+
656
+	/**
657
+	 * Adds capabilities to roles.
658
+	 *
659
+	 * @since 4.9.42
660
+	 * @param array $capabilities_to_add array of capabilities to add, indexed by roles.
661
+	 *                                   Note that this should ONLY be called on activation hook
662
+	 *                                   otherwise the caps will be added on every request.
663
+	 * @return bool
664
+	 * @throws \EE_Error
665
+	 */
666
+	public function addCaps(array $capabilities_to_add)
667
+	{
668
+		// don't do anything if the capabilities map can not be initialized
669
+		if (! $this->setupCapabilitiesMap()) {
670
+			return false;
671
+		}
672
+		// and filter the array so others can get in on the fun during resets
673
+		$capabilities_to_add = apply_filters(
674
+			'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
675
+			$capabilities_to_add,
676
+			$this->reset,
677
+			$this->capabilities_map
678
+		);
679
+		$update_capabilities_map = false;
680
+		// if not reset, see what caps are new for each role. if they're new, add them.
681
+		foreach ($capabilities_to_add as $role => $caps_for_role) {
682
+			if (is_array($caps_for_role)) {
683
+				foreach ($caps_for_role as $cap) {
684
+					if (
685
+						! $this->capHasBeenAddedToRole($role, $cap)
686
+						&& $this->add_cap_to_role($role, $cap, true, false)
687
+					) {
688
+						$update_capabilities_map = true;
689
+					}
690
+				}
691
+			}
692
+		}
693
+		// now let's just save the cap that has been set but only if there's been a change.
694
+		$updated = $this->updateCapabilitiesMap($update_capabilities_map);
695
+		do_action('AHEE__EE_Capabilities__addCaps__complete', $this->capabilities_map, $updated);
696
+		return $updated;
697
+	}
698
+
699
+
700
+
701
+	/**
702
+	 * Loops through the capabilities map and removes the role caps specified by the incoming array
703
+	 *
704
+	 * @param array $caps_map map of capabilities to be removed (indexed by roles)
705
+	 * @return bool
706
+	 * @throws \EE_Error
707
+	 */
708
+	public function removeCaps($caps_map)
709
+	{
710
+		// don't do anything if the capabilities map can not be initialized
711
+		if (! $this->setupCapabilitiesMap()) {
712
+			return false;
713
+		}
714
+		$update_capabilities_map = false;
715
+		foreach ($caps_map as $role => $caps_for_role) {
716
+			if (is_array($caps_for_role)) {
717
+				foreach ($caps_for_role as $cap) {
718
+					if (
719
+						$this->capHasBeenAddedToRole($role, $cap)
720
+						&& $this->remove_cap_from_role($role, $cap, false)
721
+					) {
722
+						$update_capabilities_map = true;
723
+					}
724
+				}
725
+			}
726
+		}
727
+		// maybe resave the caps
728
+		return $this->updateCapabilitiesMap($update_capabilities_map);
729
+	}
730
+
731
+
732
+
733
+	/**
734
+	 * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
735
+	 * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
736
+	 * this is a wrapper for $wp_role->add_cap()
737
+	 *
738
+	 * @see   wp-includes/capabilities.php
739
+	 * @since 4.5.0
740
+	 * @param string|WP_Role $role  A WordPress role the capability is being added to
741
+	 * @param string         $cap   The capability being added to the role
742
+	 * @param bool           $grant Whether to grant access to this cap on this role.
743
+	 * @param bool           $update_capabilities_map
744
+	 * @return bool
745
+	 * @throws \EE_Error
746
+	 */
747
+	public function add_cap_to_role($role, $cap, $grant = true, $update_capabilities_map = true)
748
+	{
749
+		// capture incoming value for $role because we may need it to create a new WP_Role
750
+		$orig_role = $role;
751
+		$role = $role instanceof WP_Role ? $role : get_role($role);
752
+		//if the role isn't available then we create it.
753
+		if (! $role instanceof WP_Role) {
754
+			// if a plugin wants to create a specific role name then they should create the role before
755
+			// EE_Capabilities does.  Otherwise this function will create the role name from the slug:
756
+			// - removes any `ee_` namespacing from the start of the slug.
757
+			// - replaces `_` with ` ` (empty space).
758
+			// - sentence case on the resulting string.
759
+			$role_label = ucwords(str_replace(array('ee_', '_'), array('', ' '), $orig_role));
760
+			$role = add_role($orig_role, $role_label);
761
+		}
762
+		if ($role instanceof WP_Role) {
763
+			// don't do anything if the capabilities map can not be initialized
764
+			if (! $this->setupCapabilitiesMap()) {
765
+				return false;
766
+			}
767
+			if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
768
+				$role->add_cap($cap, $grant);
769
+				$this->capabilities_map[ $role->name ][] = $cap;
770
+				$this->updateCapabilitiesMap($update_capabilities_map);
771
+				return true;
772
+			}
773
+		}
774
+		return false;
775
+	}
776
+
777
+
778
+
779
+	/**
780
+	 * Functions similarly to add_cap_to_role except removes cap from given role.
781
+	 * Wrapper for $wp_role->remove_cap()
782
+	 *
783
+	 * @see   wp-includes/capabilities.php
784
+	 * @since 4.5.0
785
+	 * @param string|WP_Role $role A WordPress role the capability is being removed from.
786
+	 * @param string         $cap  The capability being removed
787
+	 * @param bool           $update_capabilities_map
788
+	 * @return bool
789
+	 * @throws \EE_Error
790
+	 */
791
+	public function remove_cap_from_role($role, $cap, $update_capabilities_map = true)
792
+	{
793
+		// don't do anything if the capabilities map can not be initialized
794
+		if (! $this->setupCapabilitiesMap()) {
795
+			return false;
796
+		}
797
+		$role = $role instanceof WP_Role ? $role :get_role($role);
798
+		if ($index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
799
+			$role->remove_cap($cap);
800
+			unset($this->capabilities_map[ $role->name ][ $index ]);
801
+			$this->updateCapabilitiesMap($update_capabilities_map);
802
+			return true;
803
+		}
804
+		return false;
805
+	}
806
+
807
+
808
+
809
+	/**
810
+	 * @param string $role_name
811
+	 * @param string $cap
812
+	 * @param bool   $get_index
813
+	 * @return bool|mixed
814
+	 */
815
+	private function capHasBeenAddedToRole($role_name='', $cap='', $get_index = false)
816
+	{
817
+		if (
818
+			isset($this->capabilities_map[$role_name])
819
+			&& ($index = array_search($cap, $this->capabilities_map[$role_name], true)) !== false
820
+		) {
821
+			return $get_index ? $index : true;
822
+		}
823
+		return false;
824
+	}
825
+
826
+
827
+
828
+	/**
829
+	 * Wrapper for the native WP current_user_can() method.
830
+	 * This is provided as a handy method for a couple things:
831
+	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
832
+	 * write those filters wherever current_user_can is called).
833
+	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
834
+	 *
835
+	 * @since 4.5.0
836
+	 *
837
+	 * @param string $cap     The cap being checked.
838
+	 * @param string $context The context where the current_user_can is being called from.
839
+	 * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
840
+	 *                        filters.
841
+	 *
842
+	 * @return bool  Whether user can or not.
843
+	 */
844
+	public function current_user_can($cap, $context, $id = 0)
845
+	{
846
+		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
847
+		$filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id);
848
+		$filtered_cap = apply_filters(
849
+			'FHEE__EE_Capabilities__current_user_can__cap',
850
+			$filtered_cap,
851
+			$context,
852
+			$cap,
853
+			$id
854
+		);
855
+		return ! empty($id)
856
+			? current_user_can($filtered_cap, $id)
857
+			: current_user_can($filtered_cap);
858
+	}
859
+
860
+
861
+
862
+	/**
863
+	 * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
864
+	 *
865
+	 * @param int|WP_User $user    Either the user_id or a WP_User object
866
+	 * @param string      $cap     The capability string being checked
867
+	 * @param string      $context The context where the user_can is being called from (used in filters).
868
+	 * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
869
+	 *                             filters)
870
+	 *
871
+	 * @return bool Whether user can or not.
872
+	 */
873
+	public function user_can($user, $cap, $context, $id = 0)
874
+	{
875
+		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
876
+		$filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
877
+		$filtered_cap = apply_filters(
878
+			'FHEE__EE_Capabilities__user_can__cap',
879
+			$filtered_cap,
880
+			$context,
881
+			$cap,
882
+			$user,
883
+			$id
884
+		);
885
+		return ! empty($id)
886
+			? user_can($user, $filtered_cap, $id)
887
+			: user_can($user, $filtered_cap);
888
+	}
889
+
890
+
891
+
892
+	/**
893
+	 * Wrapper for the native WP current_user_can_for_blog() method.
894
+	 * This is provided as a handy method for a couple things:
895
+	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
896
+	 * write those filters wherever current_user_can is called).
897
+	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
898
+	 *
899
+	 * @since 4.5.0
900
+	 *
901
+	 * @param int    $blog_id The blog id that is being checked for.
902
+	 * @param string $cap     The cap being checked.
903
+	 * @param string $context The context where the current_user_can is being called from.
904
+	 * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
905
+	 *                        filters.
906
+	 *
907
+	 * @return bool  Whether user can or not.
908
+	 */
909
+	public function current_user_can_for_blog($blog_id, $cap, $context, $id = 0)
910
+	{
911
+		$user_can = ! empty($id)
912
+			? current_user_can_for_blog($blog_id, $cap, $id)
913
+			: current_user_can($blog_id, $cap);
914
+		//apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
915
+		$user_can = apply_filters(
916
+			'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
917
+			$user_can,
918
+			$blog_id,
919
+			$cap,
920
+			$id
921
+		);
922
+		$user_can = apply_filters(
923
+			'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
924
+			$user_can,
925
+			$context,
926
+			$blog_id,
927
+			$cap,
928
+			$id
929
+		);
930
+		return $user_can;
931
+	}
932
+
933
+
934
+
935
+	/**
936
+	 * This helper method just returns an array of registered EE capabilities.
937
+	 *
938
+	 * @since 4.5.0
939
+	 * @param string $role If empty then the entire role/capability map is returned.
940
+	 *                     Otherwise just the capabilities for the given role are returned.
941
+	 * @return array
942
+	 * @throws EE_Error
943
+	 */
944
+	public function get_ee_capabilities($role = 'administrator')
945
+	{
946
+		if (! $this->initialized) {
947
+			$this->init_caps();
948
+		}
949
+		if (empty($role)) {
950
+			return $this->capabilities_map;
951
+		}
952
+		return isset($this->capabilities_map[ $role ])
953
+			? $this->capabilities_map[ $role ]
954
+			: array();
955
+	}
956
+
957
+
958
+
959
+	/**
960
+	 * @deprecated 4.9.42
961
+	 * @param bool  $reset      If you need to reset Event Espresso's capabilities,
962
+	 *                          then please use the init_caps() method with the "$reset" parameter set to "true"
963
+	 * @param array $caps_map   Optional.
964
+	 *                          Can be used to send a custom map of roles and capabilities for setting them up.
965
+	 *                          Note that this should ONLY be called on activation hook or some other one-time
966
+	 *                          task otherwise the caps will be added on every request.
967
+	 * @return void
968
+	 * @throws EE_Error
969
+	 */
970
+	public function init_role_caps($reset = false, $caps_map = array())
971
+	{
972
+		// If this method is called directly and reset is set as 'true',
973
+		// then display a doing it wrong notice, because we want resets to go through init_caps()
974
+		// to guarantee that everything is set up correctly.
975
+		// This prevents the capabilities map getting reset incorrectly by direct calls to this method.
976
+		if ($reset) {
977
+			EE_Error::doing_it_wrong(
978
+				__METHOD__,
979
+				sprintf(
980
+					esc_html__(
981
+						'The "%1$s" parameter for the "%2$s" method is deprecated. If you need to reset Event Espresso\'s capabilities, then please use the "%3$s" method with the "%1$s" parameter set to "%4$s".',
982
+						'event_espresso'
983
+					),
984
+					'$reset',
985
+					__METHOD__ . '()',
986
+					'EE_Capabilities::init_caps()',
987
+					'true'
988
+				),
989
+				'4.9.42',
990
+				'5.0.0'
991
+			);
992
+		}
993
+		$this->addCaps($caps_map);
994
+	}
995 995
 
996 996
 
997 997
 
@@ -1012,142 +1012,142 @@  discard block
 block discarded – undo
1012 1012
 abstract class EE_Meta_Capability_Map
1013 1013
 {
1014 1014
 
1015
-    public $meta_cap;
1016
-
1017
-    /**
1018
-     * @var EEM_Base
1019
-     */
1020
-    protected $_model;
1021
-
1022
-    protected $_model_name;
1023
-
1024
-    public $published_cap = '';
1025
-
1026
-    public $others_cap = '';
1027
-
1028
-    public $private_cap = '';
1029
-
1030
-
1031
-    /**
1032
-     * constructor.
1033
-     * Receives the setup arguments for the map.
1034
-     *
1035
-     * @since                        4.5.0
1036
-     *
1037
-     * @param string $meta_cap   What meta capability is this mapping.
1038
-     * @param array  $map_values array {
1039
-     *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
1040
-     *                           capabilities that don't get mapped to.
1041
-     *
1042
-     * @type         $map_values [0] string A string representing the model name. Required.  String's
1043
-     *                               should always be used when Menu Maps are registered via the
1044
-     *                               plugin API as models are not allowed to be instantiated when
1045
-     *                               in maintenance mode 2 (migrations).
1046
-     * @type         $map_values [1] string represents the capability used for published. Optional.
1047
-     * @type         $map_values [2] string represents the capability used for "others". Optional.
1048
-     * @type         $map_values [3] string represents the capability used for private. Optional.
1049
-     *                               }
1050
-     * @throws EE_Error
1051
-     */
1052
-    public function __construct($meta_cap, $map_values)
1053
-    {
1054
-        $this->meta_cap = $meta_cap;
1055
-        //verify there are four args in the $map_values array;
1056
-        if (count($map_values) !== 4) {
1057
-            throw new EE_Error(
1058
-                sprintf(
1059
-                    __(
1060
-                        'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1061
-                        'event_espresso'
1062
-                    ),
1063
-                    '<br>' . print_r($map_values, true)
1064
-                )
1065
-            );
1066
-        }
1067
-        //set properties
1068
-        $this->_model = null;
1069
-        $this->_model_name = $map_values[0];
1070
-        $this->published_cap = (string)$map_values[1];
1071
-        $this->others_cap = (string)$map_values[2];
1072
-        $this->private_cap = (string)$map_values[3];
1073
-    }
1074
-
1075
-    /**
1076
-     * Makes it so this object stops filtering caps
1077
-     */
1078
-    public function remove_filters()
1079
-    {
1080
-        remove_filter('map_meta_cap', array($this, 'map_meta_caps'), 10);
1081
-    }
1082
-
1083
-
1084
-    /**
1085
-     * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
1086
-     *
1087
-     * @since 4.5.0
1088
-     * @throws EE_Error
1089
-     *
1090
-     * @return void
1091
-     */
1092
-    public function ensure_is_model()
1093
-    {
1094
-        //is it already instantiated?
1095
-        if ($this->_model instanceof EEM_Base) {
1096
-            return;
1097
-        }
1098
-        //ensure model name is string
1099
-        $this->_model_name = (string)$this->_model_name;
1100
-        //error proof if the name has EEM in it
1101
-        $this->_model_name = str_replace('EEM', '', $this->_model_name);
1102
-        $this->_model = EE_Registry::instance()->load_model($this->_model_name);
1103
-        if (! $this->_model instanceof EEM_Base) {
1104
-            throw new EE_Error(
1105
-                sprintf(
1106
-                    __(
1107
-                        'This string passed in to %s to represent a EEM_Base model class was not able to be used to instantiate the class.   Please ensure that the string is a match for the EEM_Base model name (not including the EEM_ part). This was given: %s',
1108
-                        'event_espresso'
1109
-                    ),
1110
-                    get_class($this),
1111
-                    $this->_model
1112
-                )
1113
-            );
1114
-        }
1115
-    }
1116
-
1117
-
1118
-    /**
1119
-     *
1120
-     * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
1121
-     * @since 4.6.x
1122
-     *
1123
-     * @param $caps
1124
-     * @param $cap
1125
-     * @param $user_id
1126
-     * @param $args
1127
-     *
1128
-     * @return array
1129
-     */
1130
-    public function map_meta_caps($caps, $cap, $user_id, $args)
1131
-    {
1132
-        return $this->_map_meta_caps($caps, $cap, $user_id, $args);
1133
-    }
1134
-
1135
-
1136
-    /**
1137
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1138
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1139
-     *
1140
-     * @since 4.5.0
1141
-     * @see   wp-includes/capabilities.php
1142
-     *
1143
-     * @param array  $caps    actual users capabilities
1144
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1145
-     * @param int    $user_id The user id
1146
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1147
-     *
1148
-     * @return array   actual users capabilities
1149
-     */
1150
-    abstract protected function _map_meta_caps($caps, $cap, $user_id, $args);
1015
+	public $meta_cap;
1016
+
1017
+	/**
1018
+	 * @var EEM_Base
1019
+	 */
1020
+	protected $_model;
1021
+
1022
+	protected $_model_name;
1023
+
1024
+	public $published_cap = '';
1025
+
1026
+	public $others_cap = '';
1027
+
1028
+	public $private_cap = '';
1029
+
1030
+
1031
+	/**
1032
+	 * constructor.
1033
+	 * Receives the setup arguments for the map.
1034
+	 *
1035
+	 * @since                        4.5.0
1036
+	 *
1037
+	 * @param string $meta_cap   What meta capability is this mapping.
1038
+	 * @param array  $map_values array {
1039
+	 *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
1040
+	 *                           capabilities that don't get mapped to.
1041
+	 *
1042
+	 * @type         $map_values [0] string A string representing the model name. Required.  String's
1043
+	 *                               should always be used when Menu Maps are registered via the
1044
+	 *                               plugin API as models are not allowed to be instantiated when
1045
+	 *                               in maintenance mode 2 (migrations).
1046
+	 * @type         $map_values [1] string represents the capability used for published. Optional.
1047
+	 * @type         $map_values [2] string represents the capability used for "others". Optional.
1048
+	 * @type         $map_values [3] string represents the capability used for private. Optional.
1049
+	 *                               }
1050
+	 * @throws EE_Error
1051
+	 */
1052
+	public function __construct($meta_cap, $map_values)
1053
+	{
1054
+		$this->meta_cap = $meta_cap;
1055
+		//verify there are four args in the $map_values array;
1056
+		if (count($map_values) !== 4) {
1057
+			throw new EE_Error(
1058
+				sprintf(
1059
+					__(
1060
+						'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1061
+						'event_espresso'
1062
+					),
1063
+					'<br>' . print_r($map_values, true)
1064
+				)
1065
+			);
1066
+		}
1067
+		//set properties
1068
+		$this->_model = null;
1069
+		$this->_model_name = $map_values[0];
1070
+		$this->published_cap = (string)$map_values[1];
1071
+		$this->others_cap = (string)$map_values[2];
1072
+		$this->private_cap = (string)$map_values[3];
1073
+	}
1074
+
1075
+	/**
1076
+	 * Makes it so this object stops filtering caps
1077
+	 */
1078
+	public function remove_filters()
1079
+	{
1080
+		remove_filter('map_meta_cap', array($this, 'map_meta_caps'), 10);
1081
+	}
1082
+
1083
+
1084
+	/**
1085
+	 * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
1086
+	 *
1087
+	 * @since 4.5.0
1088
+	 * @throws EE_Error
1089
+	 *
1090
+	 * @return void
1091
+	 */
1092
+	public function ensure_is_model()
1093
+	{
1094
+		//is it already instantiated?
1095
+		if ($this->_model instanceof EEM_Base) {
1096
+			return;
1097
+		}
1098
+		//ensure model name is string
1099
+		$this->_model_name = (string)$this->_model_name;
1100
+		//error proof if the name has EEM in it
1101
+		$this->_model_name = str_replace('EEM', '', $this->_model_name);
1102
+		$this->_model = EE_Registry::instance()->load_model($this->_model_name);
1103
+		if (! $this->_model instanceof EEM_Base) {
1104
+			throw new EE_Error(
1105
+				sprintf(
1106
+					__(
1107
+						'This string passed in to %s to represent a EEM_Base model class was not able to be used to instantiate the class.   Please ensure that the string is a match for the EEM_Base model name (not including the EEM_ part). This was given: %s',
1108
+						'event_espresso'
1109
+					),
1110
+					get_class($this),
1111
+					$this->_model
1112
+				)
1113
+			);
1114
+		}
1115
+	}
1116
+
1117
+
1118
+	/**
1119
+	 *
1120
+	 * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
1121
+	 * @since 4.6.x
1122
+	 *
1123
+	 * @param $caps
1124
+	 * @param $cap
1125
+	 * @param $user_id
1126
+	 * @param $args
1127
+	 *
1128
+	 * @return array
1129
+	 */
1130
+	public function map_meta_caps($caps, $cap, $user_id, $args)
1131
+	{
1132
+		return $this->_map_meta_caps($caps, $cap, $user_id, $args);
1133
+	}
1134
+
1135
+
1136
+	/**
1137
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1138
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1139
+	 *
1140
+	 * @since 4.5.0
1141
+	 * @see   wp-includes/capabilities.php
1142
+	 *
1143
+	 * @param array  $caps    actual users capabilities
1144
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1145
+	 * @param int    $user_id The user id
1146
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1147
+	 *
1148
+	 * @return array   actual users capabilities
1149
+	 */
1150
+	abstract protected function _map_meta_caps($caps, $cap, $user_id, $args);
1151 1151
 }
1152 1152
 
1153 1153
 
@@ -1163,81 +1163,81 @@  discard block
 block discarded – undo
1163 1163
 class EE_Meta_Capability_Map_Edit extends EE_Meta_Capability_Map
1164 1164
 {
1165 1165
 
1166
-    /**
1167
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1168
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1169
-     *
1170
-     * @since 4.5.0
1171
-     * @see   wp-includes/capabilities.php
1172
-     *
1173
-     * @param array  $caps    actual users capabilities
1174
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1175
-     * @param int    $user_id The user id
1176
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1177
-     *
1178
-     * @return array   actual users capabilities
1179
-     */
1180
-    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1181
-    {
1182
-        //only process if we're checking our mapped_cap
1183
-        if ($cap !== $this->meta_cap) {
1184
-            return $caps;
1185
-        }
1186
-
1187
-        //okay it is a meta cap so let's first remove that cap from the $caps array.
1188
-        if (($key = array_search($cap, $caps)) !== false) {
1189
-            unset($caps[$key]);
1190
-        }
1191
-
1192
-        //cast $user_id to int for later explicit comparisons
1193
-        $user_id = (int) $user_id;
1194
-
1195
-        /** @var EE_Base_Class $obj */
1196
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1197
-        //if no obj then let's just do cap
1198
-        if (! $obj instanceof EE_Base_Class) {
1199
-            $caps[] = 'do_not_allow';
1200
-            return $caps;
1201
-        }
1202
-        $caps[] = $cap . 's';
1203
-        if ($obj instanceof EE_CPT_Base) {
1204
-            //if the item author is set and the user is the author...
1205
-            if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1206
-                //if obj is published...
1207
-                if ($obj->status() === 'publish') {
1208
-                    $caps[] = $this->published_cap;
1209
-                }
1210
-            } else {
1211
-                //the user is trying to edit someone else's obj
1212
-                if (! empty($this->others_cap)) {
1213
-                    $caps[] = $this->others_cap;
1214
-                }
1215
-                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1216
-                    $caps[] = $this->published_cap;
1217
-                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1218
-                    $caps[] = $this->private_cap;
1219
-                }
1220
-            }
1221
-        } else {
1222
-            //not a cpt object so handled differently
1223
-            $has_cap = false;
1224
-            try {
1225
-                $has_cap = method_exists($obj, 'wp_user')
1226
-                    && $obj->wp_user()
1227
-                    && $obj->wp_user() === $user_id;
1228
-            } catch (Exception $e) {
1229
-                if (WP_DEBUG) {
1230
-                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1231
-                }
1232
-            }
1233
-            if (! $has_cap) {
1234
-                if (! empty($this->others_cap)) {
1235
-                    $caps[] = $this->others_cap;
1236
-                }
1237
-            }
1238
-        }
1239
-        return $caps;
1240
-    }
1166
+	/**
1167
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1168
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1169
+	 *
1170
+	 * @since 4.5.0
1171
+	 * @see   wp-includes/capabilities.php
1172
+	 *
1173
+	 * @param array  $caps    actual users capabilities
1174
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1175
+	 * @param int    $user_id The user id
1176
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1177
+	 *
1178
+	 * @return array   actual users capabilities
1179
+	 */
1180
+	protected function _map_meta_caps($caps, $cap, $user_id, $args)
1181
+	{
1182
+		//only process if we're checking our mapped_cap
1183
+		if ($cap !== $this->meta_cap) {
1184
+			return $caps;
1185
+		}
1186
+
1187
+		//okay it is a meta cap so let's first remove that cap from the $caps array.
1188
+		if (($key = array_search($cap, $caps)) !== false) {
1189
+			unset($caps[$key]);
1190
+		}
1191
+
1192
+		//cast $user_id to int for later explicit comparisons
1193
+		$user_id = (int) $user_id;
1194
+
1195
+		/** @var EE_Base_Class $obj */
1196
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1197
+		//if no obj then let's just do cap
1198
+		if (! $obj instanceof EE_Base_Class) {
1199
+			$caps[] = 'do_not_allow';
1200
+			return $caps;
1201
+		}
1202
+		$caps[] = $cap . 's';
1203
+		if ($obj instanceof EE_CPT_Base) {
1204
+			//if the item author is set and the user is the author...
1205
+			if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1206
+				//if obj is published...
1207
+				if ($obj->status() === 'publish') {
1208
+					$caps[] = $this->published_cap;
1209
+				}
1210
+			} else {
1211
+				//the user is trying to edit someone else's obj
1212
+				if (! empty($this->others_cap)) {
1213
+					$caps[] = $this->others_cap;
1214
+				}
1215
+				if (! empty($this->published_cap) && $obj->status() === 'publish') {
1216
+					$caps[] = $this->published_cap;
1217
+				} elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1218
+					$caps[] = $this->private_cap;
1219
+				}
1220
+			}
1221
+		} else {
1222
+			//not a cpt object so handled differently
1223
+			$has_cap = false;
1224
+			try {
1225
+				$has_cap = method_exists($obj, 'wp_user')
1226
+					&& $obj->wp_user()
1227
+					&& $obj->wp_user() === $user_id;
1228
+			} catch (Exception $e) {
1229
+				if (WP_DEBUG) {
1230
+					EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1231
+				}
1232
+			}
1233
+			if (! $has_cap) {
1234
+				if (! empty($this->others_cap)) {
1235
+					$caps[] = $this->others_cap;
1236
+				}
1237
+			}
1238
+		}
1239
+		return $caps;
1240
+	}
1241 1241
 }
1242 1242
 
1243 1243
 
@@ -1254,24 +1254,24 @@  discard block
 block discarded – undo
1254 1254
 class EE_Meta_Capability_Map_Delete extends EE_Meta_Capability_Map_Edit
1255 1255
 {
1256 1256
 
1257
-    /**
1258
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1259
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1260
-     *
1261
-     * @since 4.5.0
1262
-     * @see   wp-includes/capabilities.php
1263
-     *
1264
-     * @param array  $caps    actual users capabilities
1265
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1266
-     * @param int    $user_id The user id
1267
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1268
-     *
1269
-     * @return array   actual users capabilities
1270
-     */
1271
-    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1272
-    {
1273
-        return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1274
-    }
1257
+	/**
1258
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1259
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1260
+	 *
1261
+	 * @since 4.5.0
1262
+	 * @see   wp-includes/capabilities.php
1263
+	 *
1264
+	 * @param array  $caps    actual users capabilities
1265
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1266
+	 * @param int    $user_id The user id
1267
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1268
+	 *
1269
+	 * @return array   actual users capabilities
1270
+	 */
1271
+	protected function _map_meta_caps($caps, $cap, $user_id, $args)
1272
+	{
1273
+		return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1274
+	}
1275 1275
 }
1276 1276
 
1277 1277
 
@@ -1287,85 +1287,85 @@  discard block
 block discarded – undo
1287 1287
 class EE_Meta_Capability_Map_Read extends EE_Meta_Capability_Map
1288 1288
 {
1289 1289
 
1290
-    /**
1291
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1292
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1293
-     *
1294
-     * @since 4.5.0
1295
-     * @see   wp-includes/capabilities.php
1296
-     *
1297
-     * @param array  $caps    actual users capabilities
1298
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1299
-     * @param int    $user_id The user id
1300
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1301
-     *
1302
-     * @return array   actual users capabilities
1303
-     */
1304
-    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1305
-    {
1306
-        //only process if we're checking our mapped cap;
1307
-        if ($cap !== $this->meta_cap) {
1308
-            return $caps;
1309
-        }
1310
-
1311
-        //okay it is a meta cap so let's first remove that cap from the $caps array.
1312
-        if (($key = array_search($cap, $caps)) !== false) {
1313
-            unset($caps[$key]);
1314
-        }
1315
-
1316
-        //cast $user_id to int for later explicit comparisons
1317
-        $user_id = (int) $user_id;
1318
-
1319
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1320
-        //if no obj then let's just do cap
1321
-        if (! $obj instanceof EE_Base_Class) {
1322
-            $caps[] = 'do_not_allow';
1323
-            return $caps;
1324
-        }
1325
-
1326
-        $caps[] = $cap . 's';
1327
-        if ($obj instanceof EE_CPT_Base) {
1328
-            $status_obj = get_post_status_object($obj->status());
1329
-            if ($status_obj->public) {
1330
-                return $caps;
1331
-            }
1332
-            //if the item author is set and the user is not the author...
1333
-            if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1334
-                if (! empty($this->others_cap)) {
1335
-                    $caps[] = $this->others_cap;
1336
-                }
1337
-            }
1338
-            //yes this means that if users created the private post, they are able to see it regardless of private cap.
1339
-            if ($status_obj->private
1340
-                && ! empty($this->private_cap)
1341
-                && $obj->wp_user() !== $user_id
1342
-            ) {
1343
-                //the user is trying to view a private object for an object they don't own.
1344
-                $caps[] = $this->private_cap;
1345
-            }
1346
-        } else {
1347
-            //not a cpt object so handled differently
1348
-            $has_cap = false;
1349
-            try {
1350
-                $has_cap = method_exists($obj, 'wp_user')
1351
-                           && $obj->wp_user()
1352
-                           && $obj->wp_user() === $user_id;
1353
-            } catch (Exception $e) {
1354
-                if (WP_DEBUG) {
1355
-                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1356
-                }
1357
-            }
1358
-            if (! $has_cap) {
1359
-                if (! empty($this->private_cap)) {
1360
-                    $caps[] = $this->private_cap;
1361
-                }
1362
-                if (! empty($this->others_cap)) {
1363
-                    $caps[] = $this->others_cap;
1364
-                }
1365
-            }
1366
-        }
1367
-        return $caps;
1368
-    }
1290
+	/**
1291
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1292
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1293
+	 *
1294
+	 * @since 4.5.0
1295
+	 * @see   wp-includes/capabilities.php
1296
+	 *
1297
+	 * @param array  $caps    actual users capabilities
1298
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1299
+	 * @param int    $user_id The user id
1300
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1301
+	 *
1302
+	 * @return array   actual users capabilities
1303
+	 */
1304
+	protected function _map_meta_caps($caps, $cap, $user_id, $args)
1305
+	{
1306
+		//only process if we're checking our mapped cap;
1307
+		if ($cap !== $this->meta_cap) {
1308
+			return $caps;
1309
+		}
1310
+
1311
+		//okay it is a meta cap so let's first remove that cap from the $caps array.
1312
+		if (($key = array_search($cap, $caps)) !== false) {
1313
+			unset($caps[$key]);
1314
+		}
1315
+
1316
+		//cast $user_id to int for later explicit comparisons
1317
+		$user_id = (int) $user_id;
1318
+
1319
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1320
+		//if no obj then let's just do cap
1321
+		if (! $obj instanceof EE_Base_Class) {
1322
+			$caps[] = 'do_not_allow';
1323
+			return $caps;
1324
+		}
1325
+
1326
+		$caps[] = $cap . 's';
1327
+		if ($obj instanceof EE_CPT_Base) {
1328
+			$status_obj = get_post_status_object($obj->status());
1329
+			if ($status_obj->public) {
1330
+				return $caps;
1331
+			}
1332
+			//if the item author is set and the user is not the author...
1333
+			if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1334
+				if (! empty($this->others_cap)) {
1335
+					$caps[] = $this->others_cap;
1336
+				}
1337
+			}
1338
+			//yes this means that if users created the private post, they are able to see it regardless of private cap.
1339
+			if ($status_obj->private
1340
+				&& ! empty($this->private_cap)
1341
+				&& $obj->wp_user() !== $user_id
1342
+			) {
1343
+				//the user is trying to view a private object for an object they don't own.
1344
+				$caps[] = $this->private_cap;
1345
+			}
1346
+		} else {
1347
+			//not a cpt object so handled differently
1348
+			$has_cap = false;
1349
+			try {
1350
+				$has_cap = method_exists($obj, 'wp_user')
1351
+						   && $obj->wp_user()
1352
+						   && $obj->wp_user() === $user_id;
1353
+			} catch (Exception $e) {
1354
+				if (WP_DEBUG) {
1355
+					EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1356
+				}
1357
+			}
1358
+			if (! $has_cap) {
1359
+				if (! empty($this->private_cap)) {
1360
+					$caps[] = $this->private_cap;
1361
+				}
1362
+				if (! empty($this->others_cap)) {
1363
+					$caps[] = $this->others_cap;
1364
+				}
1365
+			}
1366
+		}
1367
+		return $caps;
1368
+	}
1369 1369
 }
1370 1370
 
1371 1371
 
@@ -1382,56 +1382,56 @@  discard block
 block discarded – undo
1382 1382
 class EE_Meta_Capability_Map_Messages_Cap extends EE_Meta_Capability_Map
1383 1383
 {
1384 1384
 
1385
-    /**
1386
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1387
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1388
-     *
1389
-     * @since 4.5.0
1390
-     * @see   wp-includes/capabilities.php
1391
-     *
1392
-     * @param array  $caps    actual users capabilities
1393
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1394
-     * @param int    $user_id The user id
1395
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1396
-     *
1397
-     * @return array   actual users capabilities
1398
-     */
1399
-    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1400
-    {
1401
-        //only process if we're checking our mapped_cap
1402
-        if ($cap !== $this->meta_cap) {
1403
-            return $caps;
1404
-        }
1405
-
1406
-        //okay it is a meta cap so let's first remove that cap from the $caps array.
1407
-        if (($key = array_search($cap, $caps)) !== false) {
1408
-            unset($caps[$key]);
1409
-        }
1410
-
1411
-        //cast $user_id to int for later explicit comparisons
1412
-        $user_id = (int) $user_id;
1413
-
1414
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1415
-        //if no obj then let's just do cap
1416
-        if (! $obj instanceof EE_Message_Template_Group) {
1417
-            $caps[] = 'do_not_allow';
1418
-            return $caps;
1419
-        }
1420
-        $caps[] = $cap . 's';
1421
-        $is_global = $obj->is_global();
1422
-        if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1423
-            if ($is_global) {
1424
-                $caps[] = $this->private_cap;
1425
-            }
1426
-        } else {
1427
-            if ($is_global) {
1428
-                $caps[] = $this->private_cap;
1429
-            } else {
1430
-                $caps[] = $this->others_cap;
1431
-            }
1432
-        }
1433
-        return $caps;
1434
-    }
1385
+	/**
1386
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1387
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1388
+	 *
1389
+	 * @since 4.5.0
1390
+	 * @see   wp-includes/capabilities.php
1391
+	 *
1392
+	 * @param array  $caps    actual users capabilities
1393
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1394
+	 * @param int    $user_id The user id
1395
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1396
+	 *
1397
+	 * @return array   actual users capabilities
1398
+	 */
1399
+	protected function _map_meta_caps($caps, $cap, $user_id, $args)
1400
+	{
1401
+		//only process if we're checking our mapped_cap
1402
+		if ($cap !== $this->meta_cap) {
1403
+			return $caps;
1404
+		}
1405
+
1406
+		//okay it is a meta cap so let's first remove that cap from the $caps array.
1407
+		if (($key = array_search($cap, $caps)) !== false) {
1408
+			unset($caps[$key]);
1409
+		}
1410
+
1411
+		//cast $user_id to int for later explicit comparisons
1412
+		$user_id = (int) $user_id;
1413
+
1414
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1415
+		//if no obj then let's just do cap
1416
+		if (! $obj instanceof EE_Message_Template_Group) {
1417
+			$caps[] = 'do_not_allow';
1418
+			return $caps;
1419
+		}
1420
+		$caps[] = $cap . 's';
1421
+		$is_global = $obj->is_global();
1422
+		if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1423
+			if ($is_global) {
1424
+				$caps[] = $this->private_cap;
1425
+			}
1426
+		} else {
1427
+			if ($is_global) {
1428
+				$caps[] = $this->private_cap;
1429
+			} else {
1430
+				$caps[] = $this->others_cap;
1431
+			}
1432
+		}
1433
+		return $caps;
1434
+	}
1435 1435
 }
1436 1436
 
1437 1437
 
@@ -1448,40 +1448,40 @@  discard block
 block discarded – undo
1448 1448
 class EE_Meta_Capability_Map_Registration_Form_Cap extends EE_Meta_Capability_Map
1449 1449
 {
1450 1450
 
1451
-    /**
1452
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1453
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1454
-     *
1455
-     * @since 4.5.0
1456
-     * @see   wp-includes/capabilities.php
1457
-     * @param array  $caps    actual users capabilities
1458
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1459
-     * @param int    $user_id The user id
1460
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1461
-     * @return array   actual users capabilities
1462
-     */
1463
-    protected function _map_meta_caps($caps, $cap, $user_id, $args)
1464
-    {
1465
-        //only process if we're checking our mapped_cap
1466
-        if ($cap !== $this->meta_cap) {
1467
-            return $caps;
1468
-        }
1469
-        //okay it is a meta cap so let's first remove that cap from the $caps array.
1470
-        if (($key = array_search($cap, $caps)) !== false) {
1471
-            unset($caps[$key]);
1472
-        }
1473
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1474
-        //if no obj then let's just do cap
1475
-        if (! $obj instanceof EE_Base_Class) {
1476
-            $caps[] = 'do_not_allow';
1477
-            return $caps;
1478
-        }
1479
-        $caps[]    = $cap . 's';
1480
-        $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1481
-        $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1482
-        if ($is_system) {
1483
-            $caps[] = $this->private_cap;
1484
-        }
1485
-        return $caps;
1486
-    }
1451
+	/**
1452
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1453
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1454
+	 *
1455
+	 * @since 4.5.0
1456
+	 * @see   wp-includes/capabilities.php
1457
+	 * @param array  $caps    actual users capabilities
1458
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1459
+	 * @param int    $user_id The user id
1460
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1461
+	 * @return array   actual users capabilities
1462
+	 */
1463
+	protected function _map_meta_caps($caps, $cap, $user_id, $args)
1464
+	{
1465
+		//only process if we're checking our mapped_cap
1466
+		if ($cap !== $this->meta_cap) {
1467
+			return $caps;
1468
+		}
1469
+		//okay it is a meta cap so let's first remove that cap from the $caps array.
1470
+		if (($key = array_search($cap, $caps)) !== false) {
1471
+			unset($caps[$key]);
1472
+		}
1473
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1474
+		//if no obj then let's just do cap
1475
+		if (! $obj instanceof EE_Base_Class) {
1476
+			$caps[] = 'do_not_allow';
1477
+			return $caps;
1478
+		}
1479
+		$caps[]    = $cap . 's';
1480
+		$is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1481
+		$is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1482
+		if ($is_system) {
1483
+			$caps[] = $this->private_cap;
1484
+		}
1485
+		return $caps;
1486
+	}
1487 1487
 }
Please login to merge, or discard this patch.
Spacing   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
     public static function instance()
86 86
     {
87 87
         //check if instantiated, and if not do so.
88
-        if (! self::$_instance instanceof EE_Capabilities) {
88
+        if ( ! self::$_instance instanceof EE_Capabilities) {
89 89
             self::$_instance = new self();
90 90
         }
91 91
         return self::$_instance;
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
      */
118 118
     public function init_caps($reset = false)
119 119
     {
120
-        if(! EE_Maintenance_Mode::instance()->models_can_query()){
120
+        if ( ! EE_Maintenance_Mode::instance()->models_can_query()) {
121 121
             return false;
122 122
         }
123 123
         $this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             $this->_get_default_meta_caps_array()
164 164
         );
165 165
         //add filter for map_meta_caps but only if models can query.
166
-        if (! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
166
+        if ( ! has_filter('map_meta_cap', array($this, 'map_meta_caps'))) {
167 167
             add_filter('map_meta_cap', array($this, 'map_meta_caps'), 10, 4);
168 168
         }
169 169
     }
@@ -324,11 +324,11 @@  discard block
 block discarded – undo
324 324
         if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
325 325
             //loop through our _meta_caps array
326 326
             foreach ($this->_meta_caps as $meta_map) {
327
-                if (! $meta_map instanceof EE_Meta_Capability_Map) {
327
+                if ( ! $meta_map instanceof EE_Meta_Capability_Map) {
328 328
                     continue;
329 329
                 }
330 330
                 // don't load models if there is no object ID in the args
331
-                if (! empty($args[0])) {
331
+                if ( ! empty($args[0])) {
332 332
                     $meta_map->ensure_is_model();
333 333
                 }
334 334
                 $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
@@ -630,7 +630,7 @@  discard block
 block discarded – undo
630 630
     private function setupCapabilitiesMap()
631 631
     {
632 632
         // if the initialization process hasn't even started, then we need to call init_caps()
633
-        if($this->initialized === null) {
633
+        if ($this->initialized === null) {
634 634
             return $this->init_caps();
635 635
         }
636 636
         // unless resetting, get caps from db if we haven't already
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
     public function addCaps(array $capabilities_to_add)
667 667
     {
668 668
         // don't do anything if the capabilities map can not be initialized
669
-        if (! $this->setupCapabilitiesMap()) {
669
+        if ( ! $this->setupCapabilitiesMap()) {
670 670
             return false;
671 671
         }
672 672
         // and filter the array so others can get in on the fun during resets
@@ -708,7 +708,7 @@  discard block
 block discarded – undo
708 708
     public function removeCaps($caps_map)
709 709
     {
710 710
         // don't do anything if the capabilities map can not be initialized
711
-        if (! $this->setupCapabilitiesMap()) {
711
+        if ( ! $this->setupCapabilitiesMap()) {
712 712
             return false;
713 713
         }
714 714
         $update_capabilities_map = false;
@@ -750,7 +750,7 @@  discard block
 block discarded – undo
750 750
         $orig_role = $role;
751 751
         $role = $role instanceof WP_Role ? $role : get_role($role);
752 752
         //if the role isn't available then we create it.
753
-        if (! $role instanceof WP_Role) {
753
+        if ( ! $role instanceof WP_Role) {
754 754
             // if a plugin wants to create a specific role name then they should create the role before
755 755
             // EE_Capabilities does.  Otherwise this function will create the role name from the slug:
756 756
             // - removes any `ee_` namespacing from the start of the slug.
@@ -761,12 +761,12 @@  discard block
 block discarded – undo
761 761
         }
762 762
         if ($role instanceof WP_Role) {
763 763
             // don't do anything if the capabilities map can not be initialized
764
-            if (! $this->setupCapabilitiesMap()) {
764
+            if ( ! $this->setupCapabilitiesMap()) {
765 765
                 return false;
766 766
             }
767
-            if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
767
+            if ( ! $this->capHasBeenAddedToRole($role->name, $cap)) {
768 768
                 $role->add_cap($cap, $grant);
769
-                $this->capabilities_map[ $role->name ][] = $cap;
769
+                $this->capabilities_map[$role->name][] = $cap;
770 770
                 $this->updateCapabilitiesMap($update_capabilities_map);
771 771
                 return true;
772 772
             }
@@ -791,13 +791,13 @@  discard block
 block discarded – undo
791 791
     public function remove_cap_from_role($role, $cap, $update_capabilities_map = true)
792 792
     {
793 793
         // don't do anything if the capabilities map can not be initialized
794
-        if (! $this->setupCapabilitiesMap()) {
794
+        if ( ! $this->setupCapabilitiesMap()) {
795 795
             return false;
796 796
         }
797
-        $role = $role instanceof WP_Role ? $role :get_role($role);
797
+        $role = $role instanceof WP_Role ? $role : get_role($role);
798 798
         if ($index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
799 799
             $role->remove_cap($cap);
800
-            unset($this->capabilities_map[ $role->name ][ $index ]);
800
+            unset($this->capabilities_map[$role->name][$index]);
801 801
             $this->updateCapabilitiesMap($update_capabilities_map);
802 802
             return true;
803 803
         }
@@ -812,7 +812,7 @@  discard block
 block discarded – undo
812 812
      * @param bool   $get_index
813 813
      * @return bool|mixed
814 814
      */
815
-    private function capHasBeenAddedToRole($role_name='', $cap='', $get_index = false)
815
+    private function capHasBeenAddedToRole($role_name = '', $cap = '', $get_index = false)
816 816
     {
817 817
         if (
818 818
             isset($this->capabilities_map[$role_name])
@@ -844,7 +844,7 @@  discard block
 block discarded – undo
844 844
     public function current_user_can($cap, $context, $id = 0)
845 845
     {
846 846
         //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
847
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id);
847
+        $filtered_cap = apply_filters('FHEE__EE_Capabilities__current_user_can__cap__'.$context, $cap, $id);
848 848
         $filtered_cap = apply_filters(
849 849
             'FHEE__EE_Capabilities__current_user_can__cap',
850 850
             $filtered_cap,
@@ -873,7 +873,7 @@  discard block
 block discarded – undo
873 873
     public function user_can($user, $cap, $context, $id = 0)
874 874
     {
875 875
         //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
876
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
876
+        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__'.$context, $cap, $user, $id);
877 877
         $filtered_cap = apply_filters(
878 878
             'FHEE__EE_Capabilities__user_can__cap',
879 879
             $filtered_cap,
@@ -913,7 +913,7 @@  discard block
 block discarded – undo
913 913
             : current_user_can($blog_id, $cap);
914 914
         //apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
915 915
         $user_can = apply_filters(
916
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
916
+            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__'.$context,
917 917
             $user_can,
918 918
             $blog_id,
919 919
             $cap,
@@ -943,14 +943,14 @@  discard block
 block discarded – undo
943 943
      */
944 944
     public function get_ee_capabilities($role = 'administrator')
945 945
     {
946
-        if (! $this->initialized) {
946
+        if ( ! $this->initialized) {
947 947
             $this->init_caps();
948 948
         }
949 949
         if (empty($role)) {
950 950
             return $this->capabilities_map;
951 951
         }
952
-        return isset($this->capabilities_map[ $role ])
953
-            ? $this->capabilities_map[ $role ]
952
+        return isset($this->capabilities_map[$role])
953
+            ? $this->capabilities_map[$role]
954 954
             : array();
955 955
     }
956 956
 
@@ -982,7 +982,7 @@  discard block
 block discarded – undo
982 982
                         'event_espresso'
983 983
                     ),
984 984
                     '$reset',
985
-                    __METHOD__ . '()',
985
+                    __METHOD__.'()',
986 986
                     'EE_Capabilities::init_caps()',
987 987
                     'true'
988 988
                 ),
@@ -1060,16 +1060,16 @@  discard block
 block discarded – undo
1060 1060
                         'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1061 1061
                         'event_espresso'
1062 1062
                     ),
1063
-                    '<br>' . print_r($map_values, true)
1063
+                    '<br>'.print_r($map_values, true)
1064 1064
                 )
1065 1065
             );
1066 1066
         }
1067 1067
         //set properties
1068 1068
         $this->_model = null;
1069 1069
         $this->_model_name = $map_values[0];
1070
-        $this->published_cap = (string)$map_values[1];
1071
-        $this->others_cap = (string)$map_values[2];
1072
-        $this->private_cap = (string)$map_values[3];
1070
+        $this->published_cap = (string) $map_values[1];
1071
+        $this->others_cap = (string) $map_values[2];
1072
+        $this->private_cap = (string) $map_values[3];
1073 1073
     }
1074 1074
 
1075 1075
     /**
@@ -1096,11 +1096,11 @@  discard block
 block discarded – undo
1096 1096
             return;
1097 1097
         }
1098 1098
         //ensure model name is string
1099
-        $this->_model_name = (string)$this->_model_name;
1099
+        $this->_model_name = (string) $this->_model_name;
1100 1100
         //error proof if the name has EEM in it
1101 1101
         $this->_model_name = str_replace('EEM', '', $this->_model_name);
1102 1102
         $this->_model = EE_Registry::instance()->load_model($this->_model_name);
1103
-        if (! $this->_model instanceof EEM_Base) {
1103
+        if ( ! $this->_model instanceof EEM_Base) {
1104 1104
             throw new EE_Error(
1105 1105
                 sprintf(
1106 1106
                     __(
@@ -1195,11 +1195,11 @@  discard block
 block discarded – undo
1195 1195
         /** @var EE_Base_Class $obj */
1196 1196
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1197 1197
         //if no obj then let's just do cap
1198
-        if (! $obj instanceof EE_Base_Class) {
1198
+        if ( ! $obj instanceof EE_Base_Class) {
1199 1199
             $caps[] = 'do_not_allow';
1200 1200
             return $caps;
1201 1201
         }
1202
-        $caps[] = $cap . 's';
1202
+        $caps[] = $cap.'s';
1203 1203
         if ($obj instanceof EE_CPT_Base) {
1204 1204
             //if the item author is set and the user is the author...
1205 1205
             if ($obj->wp_user() && $user_id === $obj->wp_user()) {
@@ -1209,12 +1209,12 @@  discard block
 block discarded – undo
1209 1209
                 }
1210 1210
             } else {
1211 1211
                 //the user is trying to edit someone else's obj
1212
-                if (! empty($this->others_cap)) {
1212
+                if ( ! empty($this->others_cap)) {
1213 1213
                     $caps[] = $this->others_cap;
1214 1214
                 }
1215
-                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1215
+                if ( ! empty($this->published_cap) && $obj->status() === 'publish') {
1216 1216
                     $caps[] = $this->published_cap;
1217
-                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1217
+                } elseif ( ! empty($this->private_cap) && $obj->status() === 'private') {
1218 1218
                     $caps[] = $this->private_cap;
1219 1219
                 }
1220 1220
             }
@@ -1230,8 +1230,8 @@  discard block
 block discarded – undo
1230 1230
                     EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1231 1231
                 }
1232 1232
             }
1233
-            if (! $has_cap) {
1234
-                if (! empty($this->others_cap)) {
1233
+            if ( ! $has_cap) {
1234
+                if ( ! empty($this->others_cap)) {
1235 1235
                     $caps[] = $this->others_cap;
1236 1236
                 }
1237 1237
             }
@@ -1318,12 +1318,12 @@  discard block
 block discarded – undo
1318 1318
 
1319 1319
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1320 1320
         //if no obj then let's just do cap
1321
-        if (! $obj instanceof EE_Base_Class) {
1321
+        if ( ! $obj instanceof EE_Base_Class) {
1322 1322
             $caps[] = 'do_not_allow';
1323 1323
             return $caps;
1324 1324
         }
1325 1325
 
1326
-        $caps[] = $cap . 's';
1326
+        $caps[] = $cap.'s';
1327 1327
         if ($obj instanceof EE_CPT_Base) {
1328 1328
             $status_obj = get_post_status_object($obj->status());
1329 1329
             if ($status_obj->public) {
@@ -1331,7 +1331,7 @@  discard block
 block discarded – undo
1331 1331
             }
1332 1332
             //if the item author is set and the user is not the author...
1333 1333
             if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1334
-                if (! empty($this->others_cap)) {
1334
+                if ( ! empty($this->others_cap)) {
1335 1335
                     $caps[] = $this->others_cap;
1336 1336
                 }
1337 1337
             }
@@ -1355,11 +1355,11 @@  discard block
 block discarded – undo
1355 1355
                     EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1356 1356
                 }
1357 1357
             }
1358
-            if (! $has_cap) {
1359
-                if (! empty($this->private_cap)) {
1358
+            if ( ! $has_cap) {
1359
+                if ( ! empty($this->private_cap)) {
1360 1360
                     $caps[] = $this->private_cap;
1361 1361
                 }
1362
-                if (! empty($this->others_cap)) {
1362
+                if ( ! empty($this->others_cap)) {
1363 1363
                     $caps[] = $this->others_cap;
1364 1364
                 }
1365 1365
             }
@@ -1413,11 +1413,11 @@  discard block
 block discarded – undo
1413 1413
 
1414 1414
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1415 1415
         //if no obj then let's just do cap
1416
-        if (! $obj instanceof EE_Message_Template_Group) {
1416
+        if ( ! $obj instanceof EE_Message_Template_Group) {
1417 1417
             $caps[] = 'do_not_allow';
1418 1418
             return $caps;
1419 1419
         }
1420
-        $caps[] = $cap . 's';
1420
+        $caps[] = $cap.'s';
1421 1421
         $is_global = $obj->is_global();
1422 1422
         if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1423 1423
             if ($is_global) {
@@ -1472,11 +1472,11 @@  discard block
 block discarded – undo
1472 1472
         }
1473 1473
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1474 1474
         //if no obj then let's just do cap
1475
-        if (! $obj instanceof EE_Base_Class) {
1475
+        if ( ! $obj instanceof EE_Base_Class) {
1476 1476
             $caps[] = 'do_not_allow';
1477 1477
             return $caps;
1478 1478
         }
1479
-        $caps[]    = $cap . 's';
1479
+        $caps[]    = $cap.'s';
1480 1480
         $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1481 1481
         $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1482 1482
         if ($is_system) {
Please login to merge, or discard this patch.