@@ -12,368 +12,368 @@ |
||
12 | 12 | */ |
13 | 13 | class EEM_Price extends EEM_Soft_Delete_Base |
14 | 14 | { |
15 | - // private instance of the EEM_Price object |
|
16 | - protected static $_instance; |
|
15 | + // private instance of the EEM_Price object |
|
16 | + protected static $_instance; |
|
17 | 17 | |
18 | 18 | |
19 | - /** |
|
20 | - * private constructor to prevent direct creation |
|
21 | - * |
|
22 | - * @Constructor |
|
23 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
24 | - * (and any incoming timezone data that gets saved). |
|
25 | - * Note this just sends the timezone info to the date time model field objects. |
|
26 | - * Default is NULL |
|
27 | - * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
28 | - */ |
|
29 | - protected function __construct($timezone) |
|
30 | - { |
|
31 | - $this->singular_item = __('Price', 'event_espresso'); |
|
32 | - $this->plural_item = __('Prices', 'event_espresso'); |
|
19 | + /** |
|
20 | + * private constructor to prevent direct creation |
|
21 | + * |
|
22 | + * @Constructor |
|
23 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
24 | + * (and any incoming timezone data that gets saved). |
|
25 | + * Note this just sends the timezone info to the date time model field objects. |
|
26 | + * Default is NULL |
|
27 | + * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
28 | + */ |
|
29 | + protected function __construct($timezone) |
|
30 | + { |
|
31 | + $this->singular_item = __('Price', 'event_espresso'); |
|
32 | + $this->plural_item = __('Prices', 'event_espresso'); |
|
33 | 33 | |
34 | - $this->_tables = [ |
|
35 | - 'Price' => new EE_Primary_Table('esp_price', 'PRC_ID'), |
|
36 | - ]; |
|
37 | - $this->_fields = [ |
|
38 | - 'Price' => [ |
|
39 | - 'PRC_ID' => new EE_Primary_Key_Int_Field( |
|
40 | - 'PRC_ID', |
|
41 | - 'Price ID' |
|
42 | - ), |
|
43 | - 'PRT_ID' => new EE_Foreign_Key_Int_Field( |
|
44 | - 'PRT_ID', |
|
45 | - esc_html__('Price type Id', 'event_espresso'), |
|
46 | - false, |
|
47 | - null, |
|
48 | - 'Price_Type' |
|
49 | - ), |
|
50 | - 'PRC_amount' => new EE_Money_Field( |
|
51 | - 'PRC_amount', |
|
52 | - esc_html__('Price Amount', 'event_espresso'), |
|
53 | - false, |
|
54 | - 0 |
|
55 | - ), |
|
56 | - 'PRC_name' => new EE_Plain_Text_Field( |
|
57 | - 'PRC_name', |
|
58 | - esc_html__('Name of Price', 'event_espresso'), |
|
59 | - false, |
|
60 | - '' |
|
61 | - ), |
|
62 | - 'PRC_desc' => new EE_Post_Content_Field( |
|
63 | - 'PRC_desc', |
|
64 | - esc_html__('Price Description', 'event_espresso'), |
|
65 | - false, |
|
66 | - '' |
|
67 | - ), |
|
68 | - 'PRC_is_default' => new EE_Boolean_Field( |
|
69 | - 'PRC_is_default', |
|
70 | - esc_html__('Flag indicating whether price is a default price', 'event_espresso'), |
|
71 | - false, |
|
72 | - false |
|
73 | - ), |
|
74 | - 'PRC_overrides' => new EE_Integer_Field( |
|
75 | - 'PRC_overrides', |
|
76 | - esc_html__( |
|
77 | - 'Price ID for a global Price that will be overridden by this Price ( for replacing default prices )', |
|
78 | - 'event_espresso' |
|
79 | - ), |
|
80 | - true, |
|
81 | - 0 |
|
82 | - ), |
|
83 | - 'PRC_order' => new EE_Integer_Field( |
|
84 | - 'PRC_order', |
|
85 | - esc_html__( |
|
86 | - 'Order of Application of Price (lower numbers apply first?)', |
|
87 | - 'event_espresso' |
|
88 | - ), |
|
89 | - false, |
|
90 | - 1 |
|
91 | - ), |
|
92 | - 'PRC_deleted' => new EE_Trashed_Flag_Field( |
|
93 | - 'PRC_deleted', |
|
94 | - esc_html__('Flag Indicating if this has been deleted or not', 'event_espresso'), |
|
95 | - false, |
|
96 | - false |
|
97 | - ), |
|
98 | - 'PRC_parent' => new EE_Integer_Field( |
|
99 | - 'PRC_parent', |
|
100 | - esc_html__('Indicates what PRC_ID is the parent of this PRC_ID', 'event_espresso'), |
|
101 | - true, |
|
102 | - 0 |
|
103 | - ), |
|
104 | - 'PRC_wp_user' => new EE_WP_User_Field( |
|
105 | - 'PRC_wp_user', |
|
106 | - esc_html__('Price Creator ID', 'event_espresso'), |
|
107 | - false |
|
108 | - ), |
|
109 | - ], |
|
110 | - ]; |
|
111 | - $this->_model_relations = [ |
|
112 | - 'Ticket' => new EE_HABTM_Relation('Ticket_Price'), |
|
113 | - 'Price_Type' => new EE_Belongs_To_Relation(), |
|
114 | - 'WP_User' => new EE_Belongs_To_Relation(), |
|
115 | - ]; |
|
116 | - // this model is generally available for reading |
|
117 | - $this->_cap_restriction_generators[ EEM_Base::caps_read ] = |
|
118 | - new EE_Restriction_Generator_Default_Public( |
|
119 | - 'PRC_is_default', |
|
120 | - 'Ticket.Datetime.Event' |
|
121 | - ); |
|
122 | - // account for default tickets in the caps |
|
123 | - $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = |
|
124 | - new EE_Restriction_Generator_Default_Protected( |
|
125 | - 'PRC_is_default', |
|
126 | - 'Ticket.Datetime.Event' |
|
127 | - ); |
|
128 | - $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = |
|
129 | - new EE_Restriction_Generator_Default_Protected( |
|
130 | - 'PRC_is_default', |
|
131 | - 'Ticket.Datetime.Event' |
|
132 | - ); |
|
133 | - $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = |
|
134 | - new EE_Restriction_Generator_Default_Protected( |
|
135 | - 'PRC_is_default', |
|
136 | - 'Ticket.Datetime.Event' |
|
137 | - ); |
|
138 | - parent::__construct($timezone); |
|
139 | - } |
|
34 | + $this->_tables = [ |
|
35 | + 'Price' => new EE_Primary_Table('esp_price', 'PRC_ID'), |
|
36 | + ]; |
|
37 | + $this->_fields = [ |
|
38 | + 'Price' => [ |
|
39 | + 'PRC_ID' => new EE_Primary_Key_Int_Field( |
|
40 | + 'PRC_ID', |
|
41 | + 'Price ID' |
|
42 | + ), |
|
43 | + 'PRT_ID' => new EE_Foreign_Key_Int_Field( |
|
44 | + 'PRT_ID', |
|
45 | + esc_html__('Price type Id', 'event_espresso'), |
|
46 | + false, |
|
47 | + null, |
|
48 | + 'Price_Type' |
|
49 | + ), |
|
50 | + 'PRC_amount' => new EE_Money_Field( |
|
51 | + 'PRC_amount', |
|
52 | + esc_html__('Price Amount', 'event_espresso'), |
|
53 | + false, |
|
54 | + 0 |
|
55 | + ), |
|
56 | + 'PRC_name' => new EE_Plain_Text_Field( |
|
57 | + 'PRC_name', |
|
58 | + esc_html__('Name of Price', 'event_espresso'), |
|
59 | + false, |
|
60 | + '' |
|
61 | + ), |
|
62 | + 'PRC_desc' => new EE_Post_Content_Field( |
|
63 | + 'PRC_desc', |
|
64 | + esc_html__('Price Description', 'event_espresso'), |
|
65 | + false, |
|
66 | + '' |
|
67 | + ), |
|
68 | + 'PRC_is_default' => new EE_Boolean_Field( |
|
69 | + 'PRC_is_default', |
|
70 | + esc_html__('Flag indicating whether price is a default price', 'event_espresso'), |
|
71 | + false, |
|
72 | + false |
|
73 | + ), |
|
74 | + 'PRC_overrides' => new EE_Integer_Field( |
|
75 | + 'PRC_overrides', |
|
76 | + esc_html__( |
|
77 | + 'Price ID for a global Price that will be overridden by this Price ( for replacing default prices )', |
|
78 | + 'event_espresso' |
|
79 | + ), |
|
80 | + true, |
|
81 | + 0 |
|
82 | + ), |
|
83 | + 'PRC_order' => new EE_Integer_Field( |
|
84 | + 'PRC_order', |
|
85 | + esc_html__( |
|
86 | + 'Order of Application of Price (lower numbers apply first?)', |
|
87 | + 'event_espresso' |
|
88 | + ), |
|
89 | + false, |
|
90 | + 1 |
|
91 | + ), |
|
92 | + 'PRC_deleted' => new EE_Trashed_Flag_Field( |
|
93 | + 'PRC_deleted', |
|
94 | + esc_html__('Flag Indicating if this has been deleted or not', 'event_espresso'), |
|
95 | + false, |
|
96 | + false |
|
97 | + ), |
|
98 | + 'PRC_parent' => new EE_Integer_Field( |
|
99 | + 'PRC_parent', |
|
100 | + esc_html__('Indicates what PRC_ID is the parent of this PRC_ID', 'event_espresso'), |
|
101 | + true, |
|
102 | + 0 |
|
103 | + ), |
|
104 | + 'PRC_wp_user' => new EE_WP_User_Field( |
|
105 | + 'PRC_wp_user', |
|
106 | + esc_html__('Price Creator ID', 'event_espresso'), |
|
107 | + false |
|
108 | + ), |
|
109 | + ], |
|
110 | + ]; |
|
111 | + $this->_model_relations = [ |
|
112 | + 'Ticket' => new EE_HABTM_Relation('Ticket_Price'), |
|
113 | + 'Price_Type' => new EE_Belongs_To_Relation(), |
|
114 | + 'WP_User' => new EE_Belongs_To_Relation(), |
|
115 | + ]; |
|
116 | + // this model is generally available for reading |
|
117 | + $this->_cap_restriction_generators[ EEM_Base::caps_read ] = |
|
118 | + new EE_Restriction_Generator_Default_Public( |
|
119 | + 'PRC_is_default', |
|
120 | + 'Ticket.Datetime.Event' |
|
121 | + ); |
|
122 | + // account for default tickets in the caps |
|
123 | + $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = |
|
124 | + new EE_Restriction_Generator_Default_Protected( |
|
125 | + 'PRC_is_default', |
|
126 | + 'Ticket.Datetime.Event' |
|
127 | + ); |
|
128 | + $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = |
|
129 | + new EE_Restriction_Generator_Default_Protected( |
|
130 | + 'PRC_is_default', |
|
131 | + 'Ticket.Datetime.Event' |
|
132 | + ); |
|
133 | + $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = |
|
134 | + new EE_Restriction_Generator_Default_Protected( |
|
135 | + 'PRC_is_default', |
|
136 | + 'Ticket.Datetime.Event' |
|
137 | + ); |
|
138 | + parent::__construct($timezone); |
|
139 | + } |
|
140 | 140 | |
141 | 141 | |
142 | - /** |
|
143 | - * instantiate a new price object with blank/empty properties |
|
144 | - * |
|
145 | - * @return mixed array on success, FALSE on fail |
|
146 | - */ |
|
147 | - public function get_new_price() |
|
148 | - { |
|
149 | - return $this->create_default_object(); |
|
150 | - } |
|
142 | + /** |
|
143 | + * instantiate a new price object with blank/empty properties |
|
144 | + * |
|
145 | + * @return mixed array on success, FALSE on fail |
|
146 | + */ |
|
147 | + public function get_new_price() |
|
148 | + { |
|
149 | + return $this->create_default_object(); |
|
150 | + } |
|
151 | 151 | |
152 | 152 | |
153 | - /** |
|
154 | - * retrieve ALL prices from db |
|
155 | - * |
|
156 | - * @return EE_Base_Class[]|EE_PRice[] |
|
157 | - * @throws EE_Error |
|
158 | - */ |
|
159 | - public function get_all_prices() |
|
160 | - { |
|
161 | - // retrieve all prices |
|
162 | - return $this->get_all(['order_by' => ['PRC_amount' => 'ASC']]); |
|
163 | - } |
|
153 | + /** |
|
154 | + * retrieve ALL prices from db |
|
155 | + * |
|
156 | + * @return EE_Base_Class[]|EE_PRice[] |
|
157 | + * @throws EE_Error |
|
158 | + */ |
|
159 | + public function get_all_prices() |
|
160 | + { |
|
161 | + // retrieve all prices |
|
162 | + return $this->get_all(['order_by' => ['PRC_amount' => 'ASC']]); |
|
163 | + } |
|
164 | 164 | |
165 | 165 | |
166 | - /** |
|
167 | - * retrieve all active prices for a particular event |
|
168 | - * |
|
169 | - * @param int $EVT_ID |
|
170 | - * @return array on success |
|
171 | - * @throws EE_Error |
|
172 | - */ |
|
173 | - public function get_all_event_prices($EVT_ID = 0) |
|
174 | - { |
|
175 | - return $this->get_all( |
|
176 | - [ |
|
177 | - [ |
|
178 | - 'EVT_ID' => $EVT_ID, |
|
179 | - 'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax], |
|
180 | - ], |
|
181 | - 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
182 | - ] |
|
183 | - ); |
|
184 | - } |
|
166 | + /** |
|
167 | + * retrieve all active prices for a particular event |
|
168 | + * |
|
169 | + * @param int $EVT_ID |
|
170 | + * @return array on success |
|
171 | + * @throws EE_Error |
|
172 | + */ |
|
173 | + public function get_all_event_prices($EVT_ID = 0) |
|
174 | + { |
|
175 | + return $this->get_all( |
|
176 | + [ |
|
177 | + [ |
|
178 | + 'EVT_ID' => $EVT_ID, |
|
179 | + 'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax], |
|
180 | + ], |
|
181 | + 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
182 | + ] |
|
183 | + ); |
|
184 | + } |
|
185 | 185 | |
186 | 186 | |
187 | - /** |
|
188 | - * retrieve all active global prices (that are not taxes (PBT_ID=4)) for a particular event |
|
189 | - * |
|
190 | - * @param boolean $count return count |
|
191 | - * @param bool $include_taxes |
|
192 | - * @return bool|EE_Base_Class[]|EE_PRice[] |
|
193 | - * @throws EE_Error |
|
194 | - */ |
|
195 | - public function get_all_default_prices($count = false, $include_taxes = false) |
|
196 | - { |
|
197 | - $_where = [ |
|
198 | - 'PRC_deleted' => 0, |
|
199 | - 'PRC_is_default' => 1, |
|
200 | - ]; |
|
201 | - if (! $include_taxes) { |
|
202 | - $_where['Price_Type.PBT_ID'] = ['!=', 4]; |
|
203 | - } |
|
204 | - $_query_params = [ |
|
205 | - $_where, |
|
206 | - 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
207 | - ]; |
|
208 | - return $count ? $this->count([$_where]) : $this->get_all($_query_params); |
|
209 | - } |
|
187 | + /** |
|
188 | + * retrieve all active global prices (that are not taxes (PBT_ID=4)) for a particular event |
|
189 | + * |
|
190 | + * @param boolean $count return count |
|
191 | + * @param bool $include_taxes |
|
192 | + * @return bool|EE_Base_Class[]|EE_PRice[] |
|
193 | + * @throws EE_Error |
|
194 | + */ |
|
195 | + public function get_all_default_prices($count = false, $include_taxes = false) |
|
196 | + { |
|
197 | + $_where = [ |
|
198 | + 'PRC_deleted' => 0, |
|
199 | + 'PRC_is_default' => 1, |
|
200 | + ]; |
|
201 | + if (! $include_taxes) { |
|
202 | + $_where['Price_Type.PBT_ID'] = ['!=', 4]; |
|
203 | + } |
|
204 | + $_query_params = [ |
|
205 | + $_where, |
|
206 | + 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
207 | + ]; |
|
208 | + return $count ? $this->count([$_where]) : $this->get_all($_query_params); |
|
209 | + } |
|
210 | 210 | |
211 | 211 | |
212 | - /** |
|
213 | - * retrieve all active global prices that are taxes |
|
214 | - * |
|
215 | - * @return bool|EE_Base_Class[]|EE_PRice[] |
|
216 | - * @throws EE_Error |
|
217 | - * @since 5.0.0.p |
|
218 | - */ |
|
219 | - public function getAllDefaultTaxes() |
|
220 | - { |
|
221 | - return $this->get_all( |
|
222 | - [ |
|
223 | - [ |
|
224 | - 'PRC_deleted' => 0, |
|
225 | - 'PRC_is_default' => 1, |
|
226 | - 'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax |
|
227 | - ], |
|
228 | - 'order_by' => [ |
|
229 | - 'Price_Type.PRT_order' => 'ASC', |
|
230 | - 'PRC_order' => 'ASC' |
|
231 | - ], |
|
232 | - ] |
|
233 | - ); |
|
234 | - } |
|
212 | + /** |
|
213 | + * retrieve all active global prices that are taxes |
|
214 | + * |
|
215 | + * @return bool|EE_Base_Class[]|EE_PRice[] |
|
216 | + * @throws EE_Error |
|
217 | + * @since 5.0.0.p |
|
218 | + */ |
|
219 | + public function getAllDefaultTaxes() |
|
220 | + { |
|
221 | + return $this->get_all( |
|
222 | + [ |
|
223 | + [ |
|
224 | + 'PRC_deleted' => 0, |
|
225 | + 'PRC_is_default' => 1, |
|
226 | + 'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax |
|
227 | + ], |
|
228 | + 'order_by' => [ |
|
229 | + 'Price_Type.PRT_order' => 'ASC', |
|
230 | + 'PRC_order' => 'ASC' |
|
231 | + ], |
|
232 | + ] |
|
233 | + ); |
|
234 | + } |
|
235 | 235 | |
236 | 236 | |
237 | - /** |
|
238 | - * retrieve all prices that are taxes |
|
239 | - * |
|
240 | - * @return EE_Base_Class[]|EE_PRice[] |
|
241 | - * @throws EE_Error |
|
242 | - * @throws InvalidArgumentException |
|
243 | - * @throws ReflectionException |
|
244 | - * @throws InvalidDataTypeException |
|
245 | - * @throws InvalidInterfaceException |
|
246 | - */ |
|
247 | - public function get_all_prices_that_are_taxes() |
|
248 | - { |
|
249 | - $taxes = []; |
|
250 | - $all_taxes = $this->get_all( |
|
251 | - [ |
|
252 | - ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax, 'PRC_is_default' => 1], |
|
253 | - 'order_by' => ['Price_Type.PRT_order' => 'ASC', 'PRC_order' => 'ASC'], |
|
254 | - ] |
|
255 | - ); |
|
256 | - foreach ($all_taxes as $tax) { |
|
257 | - if ($tax instanceof EE_Price) { |
|
258 | - $taxes[ $tax->order() ][ $tax->ID() ] = $tax; |
|
259 | - } |
|
260 | - } |
|
261 | - return $taxes; |
|
262 | - } |
|
237 | + /** |
|
238 | + * retrieve all prices that are taxes |
|
239 | + * |
|
240 | + * @return EE_Base_Class[]|EE_PRice[] |
|
241 | + * @throws EE_Error |
|
242 | + * @throws InvalidArgumentException |
|
243 | + * @throws ReflectionException |
|
244 | + * @throws InvalidDataTypeException |
|
245 | + * @throws InvalidInterfaceException |
|
246 | + */ |
|
247 | + public function get_all_prices_that_are_taxes() |
|
248 | + { |
|
249 | + $taxes = []; |
|
250 | + $all_taxes = $this->get_all( |
|
251 | + [ |
|
252 | + ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax, 'PRC_is_default' => 1], |
|
253 | + 'order_by' => ['Price_Type.PRT_order' => 'ASC', 'PRC_order' => 'ASC'], |
|
254 | + ] |
|
255 | + ); |
|
256 | + foreach ($all_taxes as $tax) { |
|
257 | + if ($tax instanceof EE_Price) { |
|
258 | + $taxes[ $tax->order() ][ $tax->ID() ] = $tax; |
|
259 | + } |
|
260 | + } |
|
261 | + return $taxes; |
|
262 | + } |
|
263 | 263 | |
264 | 264 | |
265 | - /** |
|
266 | - * retrieve all prices for an ticket plus default global prices, but not taxes |
|
267 | - * |
|
268 | - * @param int $TKT_ID the id of the event. If not included then we assume that this is a new ticket. |
|
269 | - * @return EE_Base_Class[]|EE_PRice[]|boolean |
|
270 | - * @throws EE_Error |
|
271 | - */ |
|
272 | - public function get_all_ticket_prices_for_admin($TKT_ID = 0) |
|
273 | - { |
|
274 | - $array_of_price_objects = []; |
|
275 | - if (empty($TKT_ID)) { |
|
276 | - // if there is no tkt, get prices with no tkt ID, are global, are not a tax, and are active |
|
277 | - // return that list |
|
278 | - $default_prices = $this->get_all_default_prices(); |
|
265 | + /** |
|
266 | + * retrieve all prices for an ticket plus default global prices, but not taxes |
|
267 | + * |
|
268 | + * @param int $TKT_ID the id of the event. If not included then we assume that this is a new ticket. |
|
269 | + * @return EE_Base_Class[]|EE_PRice[]|boolean |
|
270 | + * @throws EE_Error |
|
271 | + */ |
|
272 | + public function get_all_ticket_prices_for_admin($TKT_ID = 0) |
|
273 | + { |
|
274 | + $array_of_price_objects = []; |
|
275 | + if (empty($TKT_ID)) { |
|
276 | + // if there is no tkt, get prices with no tkt ID, are global, are not a tax, and are active |
|
277 | + // return that list |
|
278 | + $default_prices = $this->get_all_default_prices(); |
|
279 | 279 | |
280 | - if ($default_prices) { |
|
281 | - foreach ($default_prices as $price) { |
|
282 | - if ($price instanceof EE_Price) { |
|
283 | - $array_of_price_objects[ $price->type() ][] = $price; |
|
284 | - } |
|
285 | - } |
|
286 | - return $array_of_price_objects; |
|
287 | - } |
|
288 | - return []; |
|
289 | - } |
|
290 | - $ticket_prices = $this->get_all( |
|
291 | - [ |
|
292 | - [ |
|
293 | - 'TKT_ID' => $TKT_ID, |
|
294 | - 'PRC_deleted' => 0, |
|
295 | - ], |
|
296 | - 'order_by' => ['PRC_order' => 'ASC'], |
|
297 | - ] |
|
298 | - ); |
|
280 | + if ($default_prices) { |
|
281 | + foreach ($default_prices as $price) { |
|
282 | + if ($price instanceof EE_Price) { |
|
283 | + $array_of_price_objects[ $price->type() ][] = $price; |
|
284 | + } |
|
285 | + } |
|
286 | + return $array_of_price_objects; |
|
287 | + } |
|
288 | + return []; |
|
289 | + } |
|
290 | + $ticket_prices = $this->get_all( |
|
291 | + [ |
|
292 | + [ |
|
293 | + 'TKT_ID' => $TKT_ID, |
|
294 | + 'PRC_deleted' => 0, |
|
295 | + ], |
|
296 | + 'order_by' => ['PRC_order' => 'ASC'], |
|
297 | + ] |
|
298 | + ); |
|
299 | 299 | |
300 | - if (! empty($ticket_prices)) { |
|
301 | - foreach ($ticket_prices as $price) { |
|
302 | - if ($price instanceof EE_Price) { |
|
303 | - $array_of_price_objects[ $price->type() ][] = $price; |
|
304 | - } |
|
305 | - } |
|
306 | - return $array_of_price_objects; |
|
307 | - } |
|
308 | - return false; |
|
309 | - } |
|
300 | + if (! empty($ticket_prices)) { |
|
301 | + foreach ($ticket_prices as $price) { |
|
302 | + if ($price instanceof EE_Price) { |
|
303 | + $array_of_price_objects[ $price->type() ][] = $price; |
|
304 | + } |
|
305 | + } |
|
306 | + return $array_of_price_objects; |
|
307 | + } |
|
308 | + return false; |
|
309 | + } |
|
310 | 310 | |
311 | 311 | |
312 | - /** |
|
313 | - * _sort_event_prices_by_type |
|
314 | - * |
|
315 | - * @param EE_Price $price_a |
|
316 | - * @param EE_Price $price_b |
|
317 | - * @return bool false on fail |
|
318 | - */ |
|
319 | - public function _sort_event_prices_by_type(EE_Price $price_a, EE_Price $price_b) |
|
320 | - { |
|
321 | - if ($price_a->type_obj()->order() === $price_b->type_obj()->order()) { |
|
322 | - return $this->_sort_event_prices_by_order($price_a, $price_b); |
|
323 | - } |
|
324 | - return $price_a->type_obj()->order() < $price_b->type_obj()->order() ? -1 : 1; |
|
325 | - } |
|
312 | + /** |
|
313 | + * _sort_event_prices_by_type |
|
314 | + * |
|
315 | + * @param EE_Price $price_a |
|
316 | + * @param EE_Price $price_b |
|
317 | + * @return bool false on fail |
|
318 | + */ |
|
319 | + public function _sort_event_prices_by_type(EE_Price $price_a, EE_Price $price_b) |
|
320 | + { |
|
321 | + if ($price_a->type_obj()->order() === $price_b->type_obj()->order()) { |
|
322 | + return $this->_sort_event_prices_by_order($price_a, $price_b); |
|
323 | + } |
|
324 | + return $price_a->type_obj()->order() < $price_b->type_obj()->order() ? -1 : 1; |
|
325 | + } |
|
326 | 326 | |
327 | 327 | |
328 | - /** |
|
329 | - * _sort_event_prices_by_order |
|
330 | - * |
|
331 | - * @param EE_Price $price_a |
|
332 | - * @param EE_Price $price_b |
|
333 | - * @return bool false on fail |
|
334 | - */ |
|
335 | - public function _sort_event_prices_by_order(EE_Price $price_a, EE_Price $price_b) |
|
336 | - { |
|
337 | - if ($price_a->order() === $price_b->order()) { |
|
338 | - return 0; |
|
339 | - } |
|
340 | - return $price_a->order() < $price_b->order() ? -1 : 1; |
|
341 | - } |
|
328 | + /** |
|
329 | + * _sort_event_prices_by_order |
|
330 | + * |
|
331 | + * @param EE_Price $price_a |
|
332 | + * @param EE_Price $price_b |
|
333 | + * @return bool false on fail |
|
334 | + */ |
|
335 | + public function _sort_event_prices_by_order(EE_Price $price_a, EE_Price $price_b) |
|
336 | + { |
|
337 | + if ($price_a->order() === $price_b->order()) { |
|
338 | + return 0; |
|
339 | + } |
|
340 | + return $price_a->order() < $price_b->order() ? -1 : 1; |
|
341 | + } |
|
342 | 342 | |
343 | 343 | |
344 | - /** |
|
345 | - * get all prices of a specific type |
|
346 | - * |
|
347 | - * @param int $type - PRT_ID |
|
348 | - * @return EE_Base_Class[]|EE_PRice[] |
|
349 | - * @throws EE_Error |
|
350 | - */ |
|
351 | - public function get_all_prices_that_are_type($type = 0) |
|
352 | - { |
|
353 | - return $this->get_all( |
|
354 | - [ |
|
355 | - [ |
|
356 | - 'PRT_ID' => $type, |
|
357 | - ], |
|
358 | - 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
359 | - ] |
|
360 | - ); |
|
361 | - } |
|
344 | + /** |
|
345 | + * get all prices of a specific type |
|
346 | + * |
|
347 | + * @param int $type - PRT_ID |
|
348 | + * @return EE_Base_Class[]|EE_PRice[] |
|
349 | + * @throws EE_Error |
|
350 | + */ |
|
351 | + public function get_all_prices_that_are_type($type = 0) |
|
352 | + { |
|
353 | + return $this->get_all( |
|
354 | + [ |
|
355 | + [ |
|
356 | + 'PRT_ID' => $type, |
|
357 | + ], |
|
358 | + 'order_by' => $this->_order_by_array_for_get_all_method(), |
|
359 | + ] |
|
360 | + ); |
|
361 | + } |
|
362 | 362 | |
363 | 363 | |
364 | - /** |
|
365 | - * Returns an array of the normal 'order_by' query parameter provided to the get_all query. |
|
366 | - * Of course you don't have to use it, but this is the order we usually want to sort prices by |
|
367 | - * |
|
368 | - * @return array which can be used like so: $this->get_all(array(array(...where |
|
369 | - * stuff...),'order_by'=>$this->_order_by_array_for_get_all_method())); |
|
370 | - */ |
|
371 | - public function _order_by_array_for_get_all_method() |
|
372 | - { |
|
373 | - return [ |
|
374 | - 'PRC_order' => 'ASC', |
|
375 | - 'Price_Type.PRT_order' => 'ASC', |
|
376 | - 'PRC_ID' => 'ASC', |
|
377 | - ]; |
|
378 | - } |
|
364 | + /** |
|
365 | + * Returns an array of the normal 'order_by' query parameter provided to the get_all query. |
|
366 | + * Of course you don't have to use it, but this is the order we usually want to sort prices by |
|
367 | + * |
|
368 | + * @return array which can be used like so: $this->get_all(array(array(...where |
|
369 | + * stuff...),'order_by'=>$this->_order_by_array_for_get_all_method())); |
|
370 | + */ |
|
371 | + public function _order_by_array_for_get_all_method() |
|
372 | + { |
|
373 | + return [ |
|
374 | + 'PRC_order' => 'ASC', |
|
375 | + 'Price_Type.PRT_order' => 'ASC', |
|
376 | + 'PRC_ID' => 'ASC', |
|
377 | + ]; |
|
378 | + } |
|
379 | 379 | } |
@@ -14,164 +14,164 @@ |
||
14 | 14 | */ |
15 | 15 | class EE_Restriction_Generator_Default_Protected extends EE_Restriction_Generator_Base |
16 | 16 | { |
17 | - /** |
|
18 | - * Name of the field on this model (or a related model, including the model chain to it) |
|
19 | - * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
20 | - * |
|
21 | - * @var string |
|
22 | - */ |
|
23 | - protected $_default_field_name; |
|
24 | - |
|
25 | - /** |
|
26 | - * The model chain to follow to get to the event model, including the event model itself. |
|
27 | - * Eg 'Ticket.Datetime.Event' |
|
28 | - * |
|
29 | - * @var string |
|
30 | - */ |
|
31 | - protected $_path_to_event_model; |
|
32 | - |
|
33 | - |
|
34 | - /** |
|
35 | - * @param string $default_field_name the name of the field Name of the field on this model |
|
36 | - * (or a related model, including the model chain to it) |
|
37 | - * that is a boolean indicating whether or not a model object |
|
38 | - * is considered "Default" or not |
|
39 | - * @param string $path_to_event_model The model chain to follow to get to the event model, |
|
40 | - * including the event model itself. Eg 'Ticket.Datetime.Event' |
|
41 | - */ |
|
42 | - public function __construct(string $default_field_name, string $path_to_event_model) |
|
43 | - { |
|
44 | - $this->_default_field_name = $default_field_name; |
|
45 | - $this->_path_to_event_model = rtrim($path_to_event_model, '.') . '.'; |
|
46 | - } |
|
47 | - |
|
48 | - |
|
49 | - /** |
|
50 | - * @return EE_Default_Where_Conditions[]|EE_Return_None_Where_Conditions[] |
|
51 | - * @throws EE_Error |
|
52 | - */ |
|
53 | - protected function _generate_restrictions(): array |
|
54 | - { |
|
55 | - // if there are no standard caps for this model, then for now |
|
56 | - // all we know is if they need the default cap to access this |
|
57 | - if (! $this->model()->cap_slug()) { |
|
58 | - return [ |
|
59 | - self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions(), |
|
60 | - ]; |
|
61 | - } |
|
62 | - |
|
63 | - $action = $this->action(); |
|
64 | - $others = "{$action}_others"; |
|
65 | - $private = "{$action}_private"; |
|
66 | - $default = "{$action}_default"; |
|
67 | - $others_default = "{$action}_others_default"; |
|
68 | - $event_model = EEM_Event::instance(); |
|
69 | - |
|
70 | - $restrictions = [ |
|
71 | - // first: access to non-defaults is essentially controlled by which events are accessible |
|
72 | - // if they don't have the basic event cap, they can't access ANY non-default items |
|
73 | - $this->getCapKey($event_model, $action) => $this->nonDefaultRestrictions(true), |
|
74 | - // if they don't have the others event cap, they can't access others' non-default items |
|
75 | - $this->getCapKey($event_model, $others) => $this->othersNonDefaultRestrictions($event_model, $others), |
|
76 | - // if they have basic and others, but not private, they can't access others' private non-default items |
|
77 | - $this->getCapKey($event_model, $private) => $this->privateRestrictions($event_model, $private), |
|
78 | - // second: access to defaults is controlled by the default capabilities |
|
79 | - // if they don't have the default capability, restrict access to only non-default items |
|
80 | - $this->getCapKey($this->model(), $default) => $this->nonDefaultRestrictions(false), |
|
81 | - ]; |
|
82 | - // if they don't have the "others" default capability, |
|
83 | - // restrict access to only their default ones, and non-default ones |
|
84 | - if (EE_Restriction_Generator_Base::is_cap($this->model(), $others_default)) { |
|
85 | - $restrictions[ $this->getCapKey($this->model(), $others_default) ] = $this->othersDefaultRestrictions( |
|
86 | - $others_default |
|
87 | - ); |
|
88 | - } |
|
89 | - return $restrictions; |
|
90 | - } |
|
91 | - |
|
92 | - |
|
93 | - /** |
|
94 | - * @param EEM_Base $model |
|
95 | - * @param string $action |
|
96 | - * @return string |
|
97 | - * @since 5.0.0.p |
|
98 | - */ |
|
99 | - private function getCapKey(EEM_Base $model, string $action): string |
|
100 | - { |
|
101 | - return EE_Restriction_Generator_Base::get_cap_name($model, $action); |
|
102 | - } |
|
103 | - |
|
104 | - |
|
105 | - /** |
|
106 | - * @param bool $use_default_field_name |
|
107 | - * @return EE_Default_Where_Conditions |
|
108 | - * @since 5.0.0.p |
|
109 | - */ |
|
110 | - private function nonDefaultRestrictions(bool $use_default_field_name): EE_Default_Where_Conditions |
|
111 | - { |
|
112 | - return new EE_Default_Where_Conditions([$this->_default_field_name => $use_default_field_name]); |
|
113 | - } |
|
114 | - |
|
115 | - |
|
116 | - /** |
|
117 | - * @param string $action |
|
118 | - * @return EE_Default_Where_Conditions |
|
119 | - * @throws EE_Error |
|
120 | - * @since 5.0.0.p |
|
121 | - */ |
|
122 | - private function othersDefaultRestrictions(string $action): EE_Default_Where_Conditions |
|
123 | - { |
|
124 | - return new EE_Default_Where_Conditions( |
|
125 | - [ |
|
126 | - // if they don't have the others default cap, they can't access others default items |
|
127 | - // (but they can access their own default items, and non-default items) |
|
128 | - 'OR*no_' . $this->getCapKey($this->model(), $action) => [ |
|
129 | - 'AND' => [ |
|
130 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
131 | - $this->_default_field_name => true, |
|
132 | - ], |
|
133 | - $this->_default_field_name => false, |
|
134 | - ], |
|
135 | - ] |
|
136 | - ); |
|
137 | - } |
|
138 | - |
|
139 | - |
|
140 | - /** |
|
141 | - * @param EEM_Event $event_model |
|
142 | - * @param string $action |
|
143 | - * @return EE_Default_Where_Conditions |
|
144 | - * @since 5.0.0.p |
|
145 | - */ |
|
146 | - private function othersNonDefaultRestrictions(EEM_Event $event_model, string $action): EE_Default_Where_Conditions |
|
147 | - { |
|
148 | - return new EE_Default_Where_Conditions( |
|
149 | - [ |
|
150 | - 'OR*no_' . $this->getCapKey($event_model, $action) => [ |
|
151 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
152 | - ], |
|
153 | - $this->_default_field_name => true, |
|
154 | - ] |
|
155 | - ); |
|
156 | - } |
|
157 | - |
|
158 | - |
|
159 | - /** |
|
160 | - * @param EEM_Event $event_model |
|
161 | - * @param string $action |
|
162 | - * @return EE_Default_Where_Conditions |
|
163 | - * @since 5.0.0.p |
|
164 | - */ |
|
165 | - private function privateRestrictions(EEM_Event $event_model, string $action): EE_Default_Where_Conditions |
|
166 | - { |
|
167 | - return new EE_Default_Where_Conditions( |
|
168 | - [ |
|
169 | - 'OR*no_' . $this->getCapKey($event_model, $action) => [ |
|
170 | - $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
171 | - $this->_path_to_event_model . 'status' => ['!=', 'private'], |
|
172 | - $this->_default_field_name => true, |
|
173 | - ], |
|
174 | - ] |
|
175 | - ); |
|
176 | - } |
|
17 | + /** |
|
18 | + * Name of the field on this model (or a related model, including the model chain to it) |
|
19 | + * that is a boolean indicating whether or not a model object is considered "Default" or not |
|
20 | + * |
|
21 | + * @var string |
|
22 | + */ |
|
23 | + protected $_default_field_name; |
|
24 | + |
|
25 | + /** |
|
26 | + * The model chain to follow to get to the event model, including the event model itself. |
|
27 | + * Eg 'Ticket.Datetime.Event' |
|
28 | + * |
|
29 | + * @var string |
|
30 | + */ |
|
31 | + protected $_path_to_event_model; |
|
32 | + |
|
33 | + |
|
34 | + /** |
|
35 | + * @param string $default_field_name the name of the field Name of the field on this model |
|
36 | + * (or a related model, including the model chain to it) |
|
37 | + * that is a boolean indicating whether or not a model object |
|
38 | + * is considered "Default" or not |
|
39 | + * @param string $path_to_event_model The model chain to follow to get to the event model, |
|
40 | + * including the event model itself. Eg 'Ticket.Datetime.Event' |
|
41 | + */ |
|
42 | + public function __construct(string $default_field_name, string $path_to_event_model) |
|
43 | + { |
|
44 | + $this->_default_field_name = $default_field_name; |
|
45 | + $this->_path_to_event_model = rtrim($path_to_event_model, '.') . '.'; |
|
46 | + } |
|
47 | + |
|
48 | + |
|
49 | + /** |
|
50 | + * @return EE_Default_Where_Conditions[]|EE_Return_None_Where_Conditions[] |
|
51 | + * @throws EE_Error |
|
52 | + */ |
|
53 | + protected function _generate_restrictions(): array |
|
54 | + { |
|
55 | + // if there are no standard caps for this model, then for now |
|
56 | + // all we know is if they need the default cap to access this |
|
57 | + if (! $this->model()->cap_slug()) { |
|
58 | + return [ |
|
59 | + self::get_default_restrictions_cap() => new EE_Return_None_Where_Conditions(), |
|
60 | + ]; |
|
61 | + } |
|
62 | + |
|
63 | + $action = $this->action(); |
|
64 | + $others = "{$action}_others"; |
|
65 | + $private = "{$action}_private"; |
|
66 | + $default = "{$action}_default"; |
|
67 | + $others_default = "{$action}_others_default"; |
|
68 | + $event_model = EEM_Event::instance(); |
|
69 | + |
|
70 | + $restrictions = [ |
|
71 | + // first: access to non-defaults is essentially controlled by which events are accessible |
|
72 | + // if they don't have the basic event cap, they can't access ANY non-default items |
|
73 | + $this->getCapKey($event_model, $action) => $this->nonDefaultRestrictions(true), |
|
74 | + // if they don't have the others event cap, they can't access others' non-default items |
|
75 | + $this->getCapKey($event_model, $others) => $this->othersNonDefaultRestrictions($event_model, $others), |
|
76 | + // if they have basic and others, but not private, they can't access others' private non-default items |
|
77 | + $this->getCapKey($event_model, $private) => $this->privateRestrictions($event_model, $private), |
|
78 | + // second: access to defaults is controlled by the default capabilities |
|
79 | + // if they don't have the default capability, restrict access to only non-default items |
|
80 | + $this->getCapKey($this->model(), $default) => $this->nonDefaultRestrictions(false), |
|
81 | + ]; |
|
82 | + // if they don't have the "others" default capability, |
|
83 | + // restrict access to only their default ones, and non-default ones |
|
84 | + if (EE_Restriction_Generator_Base::is_cap($this->model(), $others_default)) { |
|
85 | + $restrictions[ $this->getCapKey($this->model(), $others_default) ] = $this->othersDefaultRestrictions( |
|
86 | + $others_default |
|
87 | + ); |
|
88 | + } |
|
89 | + return $restrictions; |
|
90 | + } |
|
91 | + |
|
92 | + |
|
93 | + /** |
|
94 | + * @param EEM_Base $model |
|
95 | + * @param string $action |
|
96 | + * @return string |
|
97 | + * @since 5.0.0.p |
|
98 | + */ |
|
99 | + private function getCapKey(EEM_Base $model, string $action): string |
|
100 | + { |
|
101 | + return EE_Restriction_Generator_Base::get_cap_name($model, $action); |
|
102 | + } |
|
103 | + |
|
104 | + |
|
105 | + /** |
|
106 | + * @param bool $use_default_field_name |
|
107 | + * @return EE_Default_Where_Conditions |
|
108 | + * @since 5.0.0.p |
|
109 | + */ |
|
110 | + private function nonDefaultRestrictions(bool $use_default_field_name): EE_Default_Where_Conditions |
|
111 | + { |
|
112 | + return new EE_Default_Where_Conditions([$this->_default_field_name => $use_default_field_name]); |
|
113 | + } |
|
114 | + |
|
115 | + |
|
116 | + /** |
|
117 | + * @param string $action |
|
118 | + * @return EE_Default_Where_Conditions |
|
119 | + * @throws EE_Error |
|
120 | + * @since 5.0.0.p |
|
121 | + */ |
|
122 | + private function othersDefaultRestrictions(string $action): EE_Default_Where_Conditions |
|
123 | + { |
|
124 | + return new EE_Default_Where_Conditions( |
|
125 | + [ |
|
126 | + // if they don't have the others default cap, they can't access others default items |
|
127 | + // (but they can access their own default items, and non-default items) |
|
128 | + 'OR*no_' . $this->getCapKey($this->model(), $action) => [ |
|
129 | + 'AND' => [ |
|
130 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
131 | + $this->_default_field_name => true, |
|
132 | + ], |
|
133 | + $this->_default_field_name => false, |
|
134 | + ], |
|
135 | + ] |
|
136 | + ); |
|
137 | + } |
|
138 | + |
|
139 | + |
|
140 | + /** |
|
141 | + * @param EEM_Event $event_model |
|
142 | + * @param string $action |
|
143 | + * @return EE_Default_Where_Conditions |
|
144 | + * @since 5.0.0.p |
|
145 | + */ |
|
146 | + private function othersNonDefaultRestrictions(EEM_Event $event_model, string $action): EE_Default_Where_Conditions |
|
147 | + { |
|
148 | + return new EE_Default_Where_Conditions( |
|
149 | + [ |
|
150 | + 'OR*no_' . $this->getCapKey($event_model, $action) => [ |
|
151 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
152 | + ], |
|
153 | + $this->_default_field_name => true, |
|
154 | + ] |
|
155 | + ); |
|
156 | + } |
|
157 | + |
|
158 | + |
|
159 | + /** |
|
160 | + * @param EEM_Event $event_model |
|
161 | + * @param string $action |
|
162 | + * @return EE_Default_Where_Conditions |
|
163 | + * @since 5.0.0.p |
|
164 | + */ |
|
165 | + private function privateRestrictions(EEM_Event $event_model, string $action): EE_Default_Where_Conditions |
|
166 | + { |
|
167 | + return new EE_Default_Where_Conditions( |
|
168 | + [ |
|
169 | + 'OR*no_' . $this->getCapKey($event_model, $action) => [ |
|
170 | + $this->_path_to_event_model . 'EVT_wp_user' => EE_QUERY_PLACEHOLDER_CURRENT_USER, |
|
171 | + $this->_path_to_event_model . 'status' => ['!=', 'private'], |
|
172 | + $this->_default_field_name => true, |
|
173 | + ], |
|
174 | + ] |
|
175 | + ); |
|
176 | + } |
|
177 | 177 | } |
@@ -20,1002 +20,1002 @@ |
||
20 | 20 | */ |
21 | 21 | final class EE_Admin implements InterminableInterface |
22 | 22 | { |
23 | - /** |
|
24 | - * @var EE_Admin $_instance |
|
25 | - */ |
|
26 | - private static $_instance; |
|
27 | - |
|
28 | - /** |
|
29 | - * @var PersistentAdminNoticeManager $persistent_admin_notice_manager |
|
30 | - */ |
|
31 | - private $persistent_admin_notice_manager; |
|
32 | - |
|
33 | - /** |
|
34 | - * @var LoaderInterface $loader |
|
35 | - */ |
|
36 | - protected $loader; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var RequestInterface |
|
40 | - */ |
|
41 | - protected $request; |
|
42 | - |
|
43 | - |
|
44 | - /** |
|
45 | - * @singleton method used to instantiate class object |
|
46 | - * @param LoaderInterface $loader |
|
47 | - * @param RequestInterface $request |
|
48 | - * @return EE_Admin |
|
49 | - * @throws EE_Error |
|
50 | - */ |
|
51 | - public static function instance(LoaderInterface $loader = null, RequestInterface $request = null) |
|
52 | - { |
|
53 | - // check if class object is instantiated |
|
54 | - if (! EE_Admin::$_instance instanceof EE_Admin) { |
|
55 | - EE_Admin::$_instance = new EE_Admin($loader, $request); |
|
56 | - } |
|
57 | - return EE_Admin::$_instance; |
|
58 | - } |
|
59 | - |
|
60 | - |
|
61 | - /** |
|
62 | - * @return EE_Admin |
|
63 | - * @throws EE_Error |
|
64 | - */ |
|
65 | - public static function reset() |
|
66 | - { |
|
67 | - EE_Admin::$_instance = null; |
|
68 | - $loader = LoaderFactory::getLoader(); |
|
69 | - $request = $loader->getShared('EventEspresso\core\services\request\Request'); |
|
70 | - return EE_Admin::instance($loader, $request); |
|
71 | - } |
|
72 | - |
|
73 | - |
|
74 | - /** |
|
75 | - * @param LoaderInterface $loader |
|
76 | - * @param RequestInterface $request |
|
77 | - * @throws EE_Error |
|
78 | - * @throws InvalidDataTypeException |
|
79 | - * @throws InvalidInterfaceException |
|
80 | - * @throws InvalidArgumentException |
|
81 | - */ |
|
82 | - protected function __construct(LoaderInterface $loader, RequestInterface $request) |
|
83 | - { |
|
84 | - $this->loader = $loader; |
|
85 | - $this->request = $request; |
|
86 | - // define global EE_Admin constants |
|
87 | - $this->_define_all_constants(); |
|
88 | - // set autoloaders for our admin page classes based on included path information |
|
89 | - EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN); |
|
90 | - // reset Environment config (we only do this on admin page loads); |
|
91 | - EE_Registry::instance()->CFG->environment->recheck_values(); |
|
92 | - // load EE_Request_Handler early |
|
93 | - add_action('AHEE__EE_System__initialize_last', [$this, 'init']); |
|
94 | - add_action('admin_init', [$this, 'admin_init'], 100); |
|
95 | - if (! $this->request->isAjax()) { |
|
96 | - // admin hooks |
|
97 | - add_action('admin_notices', [$this, 'display_admin_notices'], 10); |
|
98 | - add_action('network_admin_notices', [$this, 'display_admin_notices'], 10); |
|
99 | - add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2); |
|
100 | - add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2); |
|
101 | - add_filter('admin_footer_text', [$this, 'espresso_admin_footer']); |
|
102 | - add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2); |
|
103 | - add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2); |
|
104 | - } |
|
105 | - do_action('AHEE__EE_Admin__loaded'); |
|
106 | - } |
|
107 | - |
|
108 | - |
|
109 | - /** |
|
110 | - * _define_all_constants |
|
111 | - * define constants that are set globally for all admin pages |
|
112 | - * |
|
113 | - * @return void |
|
114 | - */ |
|
115 | - private function _define_all_constants() |
|
116 | - { |
|
117 | - if (! defined('EE_ADMIN_URL')) { |
|
118 | - define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/'); |
|
119 | - define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/'); |
|
120 | - define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/'); |
|
121 | - define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/'); |
|
122 | - define('WP_AJAX_URL', admin_url('admin-ajax.php')); |
|
123 | - } |
|
124 | - } |
|
125 | - |
|
126 | - |
|
127 | - /** |
|
128 | - * filter_plugin_actions - adds links to the Plugins page listing |
|
129 | - * |
|
130 | - * @param array $links |
|
131 | - * @param string $plugin |
|
132 | - * @return array |
|
133 | - */ |
|
134 | - public function filter_plugin_actions($links, $plugin) |
|
135 | - { |
|
136 | - // set $main_file in stone |
|
137 | - static $main_file; |
|
138 | - // if $main_file is not set yet |
|
139 | - if (! $main_file) { |
|
140 | - $main_file = EE_PLUGIN_BASENAME; |
|
141 | - } |
|
142 | - if ($plugin === $main_file) { |
|
143 | - // compare current plugin to this one |
|
144 | - if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) { |
|
145 | - $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"' |
|
146 | - . ' title="Event Espresso is in maintenance mode. Click this link to learn why.">' |
|
147 | - . esc_html__('Maintenance Mode Active', 'event_espresso') |
|
148 | - . '</a>'; |
|
149 | - array_unshift($links, $maintenance_link); |
|
150 | - } else { |
|
151 | - $org_settings_link = '<a href="admin.php?page=espresso_general_settings">' |
|
152 | - . esc_html__('Settings', 'event_espresso') |
|
153 | - . '</a>'; |
|
154 | - $events_link = '<a href="admin.php?page=espresso_events">' |
|
155 | - . esc_html__('Events', 'event_espresso') |
|
156 | - . '</a>'; |
|
157 | - // add before other links |
|
158 | - array_unshift($links, $org_settings_link, $events_link); |
|
159 | - } |
|
160 | - } |
|
161 | - return $links; |
|
162 | - } |
|
163 | - |
|
164 | - |
|
165 | - /** |
|
166 | - * hide_admin_pages_except_maintenance_mode |
|
167 | - * |
|
168 | - * @param array $admin_page_folder_names |
|
169 | - * @return array |
|
170 | - */ |
|
171 | - public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = []) |
|
172 | - { |
|
173 | - return [ |
|
174 | - 'maintenance' => EE_ADMIN_PAGES . 'maintenance/', |
|
175 | - 'about' => EE_ADMIN_PAGES . 'about/', |
|
176 | - 'support' => EE_ADMIN_PAGES . 'support/', |
|
177 | - ]; |
|
178 | - } |
|
179 | - |
|
180 | - |
|
181 | - /** |
|
182 | - * init- should fire after shortcode, module, addon, other plugin (default priority), and even |
|
183 | - * EE_Front_Controller's init phases have run |
|
184 | - * |
|
185 | - * @return void |
|
186 | - * @throws EE_Error |
|
187 | - * @throws InvalidArgumentException |
|
188 | - * @throws InvalidDataTypeException |
|
189 | - * @throws InvalidInterfaceException |
|
190 | - * @throws ReflectionException |
|
191 | - * @throws ServiceNotFoundException |
|
192 | - */ |
|
193 | - public function init() |
|
194 | - { |
|
195 | - // only enable most of the EE_Admin IF we're not in full maintenance mode |
|
196 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
197 | - $this->initModelsReady(); |
|
198 | - } |
|
199 | - // run the admin page factory but ONLY if: |
|
200 | - // - it is a regular non ajax admin request |
|
201 | - // - we are doing an ee admin ajax request |
|
202 | - if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) { |
|
203 | - try { |
|
204 | - // this loads the controller for the admin pages which will setup routing etc |
|
205 | - $admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]); |
|
206 | - /** @var EE_Admin_Page_Loader $admin_page_loader */ |
|
207 | - $admin_page_loader->init(); |
|
208 | - } catch (EE_Error $e) { |
|
209 | - $e->get_error(); |
|
210 | - } |
|
211 | - } |
|
212 | - if ($this->request->isAjax()) { |
|
213 | - return; |
|
214 | - } |
|
215 | - add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1); |
|
216 | - // make sure our CPTs and custom taxonomy metaboxes get shown for first time users |
|
217 | - add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10); |
|
218 | - add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10); |
|
219 | - // exclude EE critical pages from all nav menus and wp_list_pages |
|
220 | - add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10); |
|
221 | - } |
|
222 | - |
|
223 | - |
|
224 | - /** |
|
225 | - * Gets the loader (and if it wasn't previously set, sets it) |
|
226 | - * |
|
227 | - * @return LoaderInterface |
|
228 | - * @throws InvalidArgumentException |
|
229 | - * @throws InvalidDataTypeException |
|
230 | - * @throws InvalidInterfaceException |
|
231 | - */ |
|
232 | - protected function getLoader() |
|
233 | - { |
|
234 | - return $this->loader; |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * Method that's fired on admin requests (including admin ajax) but only when the models are usable |
|
240 | - * (ie, the site isn't in maintenance mode) |
|
241 | - * |
|
242 | - * @return void |
|
243 | - * @throws EE_Error |
|
244 | - * @since 4.9.63.p |
|
245 | - */ |
|
246 | - protected function initModelsReady() |
|
247 | - { |
|
248 | - // ok so we want to enable the entire admin |
|
249 | - $this->persistent_admin_notice_manager = $this->loader->getShared( |
|
250 | - 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
251 | - ); |
|
252 | - $this->persistent_admin_notice_manager->setReturnUrl( |
|
253 | - EE_Admin_Page::add_query_args_and_nonce( |
|
254 | - [ |
|
255 | - 'page' => $this->request->getRequestParam('page', ''), |
|
256 | - 'action' => $this->request->getRequestParam('action', ''), |
|
257 | - ], |
|
258 | - EE_ADMIN_URL |
|
259 | - ) |
|
260 | - ); |
|
261 | - $this->maybeSetDatetimeWarningNotice(); |
|
262 | - // at a glance dashboard widget |
|
263 | - add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10); |
|
264 | - // filter for get_edit_post_link used on comments for custom post types |
|
265 | - add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2); |
|
266 | - } |
|
267 | - |
|
268 | - |
|
269 | - /** |
|
270 | - * get_persistent_admin_notices |
|
271 | - * |
|
272 | - * @access public |
|
273 | - * @return void |
|
274 | - * @throws EE_Error |
|
275 | - * @throws InvalidArgumentException |
|
276 | - * @throws InvalidDataTypeException |
|
277 | - * @throws InvalidInterfaceException |
|
278 | - */ |
|
279 | - public function maybeSetDatetimeWarningNotice() |
|
280 | - { |
|
281 | - // add dismissible notice for datetime changes. Only valid if site does not have a timezone_string set. |
|
282 | - // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version |
|
283 | - // with this. But after enough time (indeterminate at this point) we can just remove this notice. |
|
284 | - // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626 |
|
285 | - if ( |
|
286 | - apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true) |
|
287 | - && ! get_option('timezone_string') |
|
288 | - && EEM_Event::instance()->count() > 0 |
|
289 | - ) { |
|
290 | - new PersistentAdminNotice( |
|
291 | - 'datetime_fix_notice', |
|
292 | - sprintf( |
|
293 | - esc_html__( |
|
294 | - '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times. Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.', |
|
295 | - 'event_espresso' |
|
296 | - ), |
|
297 | - '<strong>', |
|
298 | - '</strong>', |
|
299 | - '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">', |
|
300 | - '</a>', |
|
301 | - '<a href="' . EE_Admin_Page::add_query_args_and_nonce( |
|
302 | - [ |
|
303 | - 'page' => 'espresso_maintenance_settings', |
|
304 | - 'action' => 'datetime_tools', |
|
305 | - ], |
|
306 | - admin_url('admin.php') |
|
307 | - ) . '">' |
|
308 | - ), |
|
309 | - false, |
|
310 | - 'manage_options', |
|
311 | - 'datetime_fix_persistent_notice' |
|
312 | - ); |
|
313 | - } |
|
314 | - } |
|
315 | - |
|
316 | - |
|
317 | - /** |
|
318 | - * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from |
|
319 | - * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in |
|
320 | - * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that |
|
321 | - * to override any queries found in the existing query for the given post type. Note that _default_query is not a |
|
322 | - * normal property on the post_type object. It's found ONLY in this particular context. |
|
323 | - * |
|
324 | - * @param WP_Post $post_type WP post type object |
|
325 | - * @return WP_Post |
|
326 | - * @throws InvalidArgumentException |
|
327 | - * @throws InvalidDataTypeException |
|
328 | - * @throws InvalidInterfaceException |
|
329 | - */ |
|
330 | - public function remove_pages_from_nav_menu($post_type) |
|
331 | - { |
|
332 | - // if this isn't the "pages" post type let's get out |
|
333 | - if ($post_type->name !== 'page') { |
|
334 | - return $post_type; |
|
335 | - } |
|
336 | - $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array(); |
|
337 | - $post_type->_default_query = [ |
|
338 | - 'post__not_in' => $critical_pages, |
|
339 | - ]; |
|
340 | - return $post_type; |
|
341 | - } |
|
342 | - |
|
343 | - |
|
344 | - /** |
|
345 | - * WP by default only shows three metaboxes in "nav-menus.php" for first times users. |
|
346 | - * We want to make sure our metaboxes get shown as well |
|
347 | - * |
|
348 | - * @return void |
|
349 | - */ |
|
350 | - public function enable_hidden_ee_nav_menu_metaboxes() |
|
351 | - { |
|
352 | - global $wp_meta_boxes, $pagenow; |
|
353 | - if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') { |
|
354 | - return; |
|
355 | - } |
|
356 | - $user = wp_get_current_user(); |
|
357 | - // has this been done yet? |
|
358 | - if (get_user_option('ee_nav_menu_initialized', $user->ID)) { |
|
359 | - return; |
|
360 | - } |
|
361 | - |
|
362 | - $hidden_meta_boxes = get_user_option('metaboxhidden_nav-menus', $user->ID); |
|
363 | - $initial_meta_boxes = apply_filters( |
|
364 | - 'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes', |
|
365 | - [ |
|
366 | - 'nav-menu-theme-locations', |
|
367 | - 'add-page', |
|
368 | - 'add-custom-links', |
|
369 | - 'add-category', |
|
370 | - 'add-espresso_events', |
|
371 | - 'add-espresso_venues', |
|
372 | - 'add-espresso_event_categories', |
|
373 | - 'add-espresso_venue_categories', |
|
374 | - 'add-post-type-post', |
|
375 | - 'add-post-type-page', |
|
376 | - ] |
|
377 | - ); |
|
378 | - |
|
379 | - if (is_array($hidden_meta_boxes)) { |
|
380 | - foreach ($hidden_meta_boxes as $key => $meta_box_id) { |
|
381 | - if (in_array($meta_box_id, $initial_meta_boxes, true)) { |
|
382 | - unset($hidden_meta_boxes[ $key ]); |
|
383 | - } |
|
384 | - } |
|
385 | - } |
|
386 | - update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true); |
|
387 | - update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true); |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - /** |
|
392 | - * This method simply registers custom nav menu boxes for "nav_menus.php route" |
|
393 | - * Currently EE is using this to make sure there are menu options for our CPT archive page routes. |
|
394 | - * |
|
395 | - * @return void |
|
396 | - * @todo modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by |
|
397 | - * addons etc. |
|
398 | - */ |
|
399 | - public function register_custom_nav_menu_boxes() |
|
400 | - { |
|
401 | - add_meta_box( |
|
402 | - 'add-extra-nav-menu-pages', |
|
403 | - esc_html__('Event Espresso Pages', 'event_espresso'), |
|
404 | - [$this, 'ee_cpt_archive_pages'], |
|
405 | - 'nav-menus', |
|
406 | - 'side', |
|
407 | - 'core' |
|
408 | - ); |
|
409 | - add_filter( |
|
410 | - "postbox_classes_nav-menus_add-extra-nav-menu-pages", |
|
411 | - function ($classes) { |
|
412 | - array_push($classes, 'ee-admin-container'); |
|
413 | - return $classes; |
|
414 | - } |
|
415 | - ); |
|
416 | - } |
|
417 | - |
|
418 | - |
|
419 | - /** |
|
420 | - * Use this to edit the post link for our cpts so that the edit link points to the correct page. |
|
421 | - * |
|
422 | - * @param string $link the original link generated by wp |
|
423 | - * @param int $id post id |
|
424 | - * @return string the (maybe) modified link |
|
425 | - * @since 4.3.0 |
|
426 | - */ |
|
427 | - public function modify_edit_post_link($link, $id) |
|
428 | - { |
|
429 | - if (! $post = get_post($id)) { |
|
430 | - return $link; |
|
431 | - } |
|
432 | - if ($post->post_type === 'espresso_attendees') { |
|
433 | - $query_args = [ |
|
434 | - 'action' => 'edit_attendee', |
|
435 | - 'post' => $id, |
|
436 | - ]; |
|
437 | - return EEH_URL::add_query_args_and_nonce( |
|
438 | - $query_args, |
|
439 | - admin_url('admin.php?page=espresso_registrations') |
|
440 | - ); |
|
441 | - } |
|
442 | - return $link; |
|
443 | - } |
|
444 | - |
|
445 | - |
|
446 | - public function ee_cpt_archive_pages() |
|
447 | - { |
|
448 | - global $nav_menu_selected_id; |
|
449 | - $removed_args = [ |
|
450 | - 'action', |
|
451 | - 'customlink-tab', |
|
452 | - 'edit-menu-item', |
|
453 | - 'menu-item', |
|
454 | - 'page-tab', |
|
455 | - '_wpnonce', |
|
456 | - ]; |
|
457 | - $nav_tab_link = $nav_menu_selected_id |
|
458 | - ? esc_url( |
|
459 | - add_query_arg( |
|
460 | - 'extra-nav-menu-pages-tab', |
|
461 | - 'event-archives', |
|
462 | - remove_query_arg($removed_args) |
|
463 | - ) |
|
464 | - ) |
|
465 | - : ''; |
|
466 | - $select_all_link = esc_url( |
|
467 | - add_query_arg( |
|
468 | - [ |
|
469 | - 'extra-nav-menu-pages-tab' => 'event-archives', |
|
470 | - 'selectall' => 1, |
|
471 | - ], |
|
472 | - remove_query_arg($removed_args) |
|
473 | - ) |
|
474 | - ); |
|
475 | - $pages = $this->_get_extra_nav_menu_pages_items(); |
|
476 | - $args['walker'] = new Walker_Nav_Menu_Checklist(false); |
|
477 | - ; |
|
478 | - $nav_menu_pages_items = walk_nav_menu_tree( |
|
479 | - array_map( |
|
480 | - [$this, '_setup_extra_nav_menu_pages_items'], |
|
481 | - $pages |
|
482 | - ), |
|
483 | - 0, |
|
484 | - (object) $args |
|
485 | - ); |
|
486 | - EEH_Template::display_template( |
|
487 | - EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php', |
|
488 | - [ |
|
489 | - 'nav_menu_selected_id' => $nav_menu_selected_id, |
|
490 | - 'nav_menu_pages_items' => $nav_menu_pages_items, |
|
491 | - 'nav_tab_link' => $nav_tab_link, |
|
492 | - 'select_all_link' => $select_all_link, |
|
493 | - ] |
|
494 | - ); |
|
495 | - } |
|
496 | - |
|
497 | - |
|
498 | - /** |
|
499 | - * Returns an array of event archive nav items. |
|
500 | - * |
|
501 | - * @return array |
|
502 | - * @todo for now this method is just in place so when it gets abstracted further we can substitute in whatever |
|
503 | - * method we use for getting the extra nav menu items |
|
504 | - */ |
|
505 | - private function _get_extra_nav_menu_pages_items() |
|
506 | - { |
|
507 | - $menuitems[] = [ |
|
508 | - 'title' => esc_html__('Event List', 'event_espresso'), |
|
509 | - 'url' => get_post_type_archive_link('espresso_events'), |
|
510 | - 'description' => esc_html__('Archive page for all events.', 'event_espresso'), |
|
511 | - ]; |
|
512 | - return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems); |
|
513 | - } |
|
514 | - |
|
515 | - |
|
516 | - /** |
|
517 | - * Setup nav menu walker item for usage in the event archive nav menu metabox. It receives a menu_item array with |
|
518 | - * the properties and converts it to the menu item object. |
|
519 | - * |
|
520 | - * @param $menu_item_values |
|
521 | - * @return stdClass |
|
522 | - * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php |
|
523 | - */ |
|
524 | - private function _setup_extra_nav_menu_pages_items($menu_item_values) |
|
525 | - { |
|
526 | - $menu_item = new stdClass(); |
|
527 | - $keys = [ |
|
528 | - 'ID' => 0, |
|
529 | - 'db_id' => 0, |
|
530 | - 'menu_item_parent' => 0, |
|
531 | - 'object_id' => -1, |
|
532 | - 'post_parent' => 0, |
|
533 | - 'type' => 'custom', |
|
534 | - 'object' => '', |
|
535 | - 'type_label' => esc_html__('Extra Nav Menu Item', 'event_espresso'), |
|
536 | - 'title' => '', |
|
537 | - 'url' => '', |
|
538 | - 'target' => '', |
|
539 | - 'attr_title' => '', |
|
540 | - 'description' => '', |
|
541 | - 'classes' => [], |
|
542 | - 'xfn' => '', |
|
543 | - ]; |
|
544 | - foreach ($keys as $key => $value) { |
|
545 | - $menu_item->{$key} = $menu_item_values[ $key ] ?? $value; |
|
546 | - } |
|
547 | - return $menu_item; |
|
548 | - } |
|
549 | - |
|
550 | - |
|
551 | - /** |
|
552 | - * admin_init |
|
553 | - * |
|
554 | - * @return void |
|
555 | - * @throws InvalidArgumentException |
|
556 | - * @throws InvalidDataTypeException |
|
557 | - * @throws InvalidInterfaceException |
|
558 | - */ |
|
559 | - public function admin_init() |
|
560 | - { |
|
561 | - /** |
|
562 | - * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php), |
|
563 | - * so any hooking into core WP routes is taken care of. So in this next few lines of code: |
|
564 | - * - check if doing post processing. |
|
565 | - * - check if doing post processing of one of EE CPTs |
|
566 | - * - instantiate the corresponding EE CPT model for the post_type being processed. |
|
567 | - */ |
|
568 | - $action = $this->request->getRequestParam('action'); |
|
569 | - $post_type = $this->request->getRequestParam('post_type'); |
|
570 | - if ($post_type && $action === 'editpost') { |
|
571 | - /** @var CustomPostTypeDefinitions $custom_post_types */ |
|
572 | - $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class); |
|
573 | - $custom_post_types->getCustomPostTypeModels($post_type); |
|
574 | - } |
|
575 | - |
|
576 | - |
|
577 | - if (! $this->request->isAjax()) { |
|
578 | - /** |
|
579 | - * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting |
|
580 | - * critical pages. The only place critical pages need included in a generated dropdown is on the "Critical |
|
581 | - * Pages" tab in the EE General Settings Admin page. |
|
582 | - * This is for user-proofing. |
|
583 | - */ |
|
584 | - add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']); |
|
585 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
586 | - $this->adminInitModelsReady(); |
|
587 | - } |
|
588 | - } |
|
589 | - } |
|
590 | - |
|
591 | - |
|
592 | - /** |
|
593 | - * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode) |
|
594 | - */ |
|
595 | - protected function adminInitModelsReady() |
|
596 | - { |
|
597 | - if (function_exists('wp_add_privacy_policy_content')) { |
|
598 | - $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager'); |
|
599 | - } |
|
600 | - } |
|
601 | - |
|
602 | - |
|
603 | - /** |
|
604 | - * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection. |
|
605 | - * |
|
606 | - * @param string $output Current output. |
|
607 | - * @return string |
|
608 | - * @throws InvalidArgumentException |
|
609 | - * @throws InvalidDataTypeException |
|
610 | - * @throws InvalidInterfaceException |
|
611 | - */ |
|
612 | - public function modify_dropdown_pages($output) |
|
613 | - { |
|
614 | - // get critical pages |
|
615 | - $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array(); |
|
616 | - |
|
617 | - // split current output by line break for easier parsing. |
|
618 | - $split_output = explode("\n", $output); |
|
619 | - |
|
620 | - // loop through to remove any critical pages from the array. |
|
621 | - foreach ($critical_pages as $page_id) { |
|
622 | - $needle = 'value="' . $page_id . '"'; |
|
623 | - foreach ($split_output as $key => $haystack) { |
|
624 | - if (strpos($haystack, $needle) !== false) { |
|
625 | - unset($split_output[ $key ]); |
|
626 | - } |
|
627 | - } |
|
628 | - } |
|
629 | - // replace output with the new contents |
|
630 | - return implode("\n", $split_output); |
|
631 | - } |
|
632 | - |
|
633 | - |
|
634 | - /** |
|
635 | - * display_admin_notices |
|
636 | - * |
|
637 | - * @return void |
|
638 | - */ |
|
639 | - public function display_admin_notices() |
|
640 | - { |
|
641 | - echo EE_Error::get_notices(); // already escaped |
|
642 | - } |
|
643 | - |
|
644 | - |
|
645 | - /** |
|
646 | - * @param array $elements |
|
647 | - * @return array |
|
648 | - * @throws EE_Error |
|
649 | - * @throws InvalidArgumentException |
|
650 | - * @throws InvalidDataTypeException |
|
651 | - * @throws InvalidInterfaceException |
|
652 | - */ |
|
653 | - public function dashboard_glance_items($elements) |
|
654 | - { |
|
655 | - $elements = is_array($elements) ? $elements : [$elements]; |
|
656 | - $events = EEM_Event::instance()->count(); |
|
657 | - $items['events']['url'] = EE_Admin_Page::add_query_args_and_nonce( |
|
658 | - ['page' => 'espresso_events'], |
|
659 | - admin_url('admin.php') |
|
660 | - ); |
|
661 | - $items['events']['text'] = sprintf( |
|
662 | - esc_html( |
|
663 | - _n('%s Event', '%s Events', $events, 'event_espresso') |
|
664 | - ), |
|
665 | - number_format_i18n($events) |
|
666 | - ); |
|
667 | - $items['events']['title'] = esc_html__('Click to view all Events', 'event_espresso'); |
|
668 | - $registrations = EEM_Registration::instance()->count( |
|
669 | - [ |
|
670 | - [ |
|
671 | - 'STS_ID' => ['!=', EEM_Registration::status_id_incomplete], |
|
672 | - ], |
|
673 | - ] |
|
674 | - ); |
|
675 | - $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce( |
|
676 | - ['page' => 'espresso_registrations'], |
|
677 | - admin_url('admin.php') |
|
678 | - ); |
|
679 | - $items['registrations']['text'] = sprintf( |
|
680 | - esc_html( |
|
681 | - _n('%s Registration', '%s Registrations', $registrations, 'event_espresso') |
|
682 | - ), |
|
683 | - number_format_i18n($registrations) |
|
684 | - ); |
|
685 | - $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso'); |
|
686 | - |
|
687 | - $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items); |
|
688 | - |
|
689 | - foreach ($items as $type => $item_properties) { |
|
690 | - $elements[] = sprintf( |
|
691 | - '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>', |
|
692 | - $item_properties['url'], |
|
693 | - $item_properties['title'], |
|
694 | - $item_properties['text'] |
|
695 | - ); |
|
696 | - } |
|
697 | - return $elements; |
|
698 | - } |
|
699 | - |
|
700 | - |
|
701 | - /** |
|
702 | - * check_for_invalid_datetime_formats |
|
703 | - * if an admin changes their date or time format settings on the WP General Settings admin page, verify that |
|
704 | - * their selected format can be parsed by PHP |
|
705 | - * |
|
706 | - * @param $value |
|
707 | - * @param $option |
|
708 | - * @return string |
|
709 | - */ |
|
710 | - public function check_for_invalid_datetime_formats($value, $option) |
|
711 | - { |
|
712 | - // check for date_format or time_format |
|
713 | - switch ($option) { |
|
714 | - case 'date_format': |
|
715 | - $date_time_format = $value . ' ' . get_option('time_format'); |
|
716 | - break; |
|
717 | - case 'time_format': |
|
718 | - $date_time_format = get_option('date_format') . ' ' . $value; |
|
719 | - break; |
|
720 | - default: |
|
721 | - $date_time_format = false; |
|
722 | - } |
|
723 | - // do we have a date_time format to check ? |
|
724 | - if ($date_time_format) { |
|
725 | - $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format); |
|
726 | - |
|
727 | - if (is_array($error_msg)) { |
|
728 | - $msg = '<p>' |
|
729 | - . sprintf( |
|
730 | - esc_html__( |
|
731 | - 'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:', |
|
732 | - 'event_espresso' |
|
733 | - ), |
|
734 | - date($date_time_format), |
|
735 | - $date_time_format |
|
736 | - ) |
|
737 | - . '</p><p><ul>'; |
|
738 | - |
|
739 | - |
|
740 | - foreach ($error_msg as $error) { |
|
741 | - $msg .= '<li>' . $error . '</li>'; |
|
742 | - } |
|
743 | - |
|
744 | - $msg .= '</ul></p><p>' |
|
745 | - . sprintf( |
|
746 | - esc_html__( |
|
747 | - '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s', |
|
748 | - 'event_espresso' |
|
749 | - ), |
|
750 | - '<span style="color:#D54E21;">', |
|
751 | - '</span>' |
|
752 | - ) |
|
753 | - . '</p>'; |
|
754 | - |
|
755 | - // trigger WP settings error |
|
756 | - add_settings_error( |
|
757 | - 'date_format', |
|
758 | - 'date_format', |
|
759 | - $msg |
|
760 | - ); |
|
761 | - |
|
762 | - // set format to something valid |
|
763 | - switch ($option) { |
|
764 | - case 'date_format': |
|
765 | - $value = 'F j, Y'; |
|
766 | - break; |
|
767 | - case 'time_format': |
|
768 | - $value = 'g:i a'; |
|
769 | - break; |
|
770 | - } |
|
771 | - } |
|
772 | - } |
|
773 | - return $value; |
|
774 | - } |
|
775 | - |
|
776 | - |
|
777 | - /** |
|
778 | - * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso" |
|
779 | - * |
|
780 | - * @param $content |
|
781 | - * @return string |
|
782 | - */ |
|
783 | - public function its_eSpresso($content) |
|
784 | - { |
|
785 | - return str_replace('[EXPRESSO_', '[ESPRESSO_', $content); |
|
786 | - } |
|
787 | - |
|
788 | - |
|
789 | - /** |
|
790 | - * espresso_admin_footer |
|
791 | - * |
|
792 | - * @return string |
|
793 | - */ |
|
794 | - public function espresso_admin_footer() |
|
795 | - { |
|
796 | - return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']); |
|
797 | - } |
|
798 | - |
|
799 | - |
|
800 | - /** |
|
801 | - * Hooks into the "post states" filter in a wp post type list table. |
|
802 | - * |
|
803 | - * @param array $post_states |
|
804 | - * @param WP_Post $post |
|
805 | - * @return array |
|
806 | - * @throws InvalidArgumentException |
|
807 | - * @throws InvalidDataTypeException |
|
808 | - * @throws InvalidInterfaceException |
|
809 | - */ |
|
810 | - public function displayStateForCriticalPages($post_states, $post) |
|
811 | - { |
|
812 | - $post_states = (array) $post_states; |
|
813 | - if (! $post instanceof WP_Post || $post->post_type !== 'page') { |
|
814 | - return $post_states; |
|
815 | - } |
|
816 | - /** @var EE_Core_Config $config */ |
|
817 | - $config = $this->loader->getShared('EE_Config')->core; |
|
818 | - if (in_array($post->ID, $config->get_critical_pages_array(), true)) { |
|
819 | - $post_states[] = sprintf( |
|
820 | - /* Translators: Using company name - Event Espresso Critical Page */ |
|
821 | - esc_html__('%s Critical Page', 'event_espresso'), |
|
822 | - 'Event Espresso' |
|
823 | - ); |
|
824 | - } |
|
825 | - return $post_states; |
|
826 | - } |
|
827 | - |
|
828 | - |
|
829 | - /** |
|
830 | - * Show documentation links on the plugins page |
|
831 | - * |
|
832 | - * @param mixed $meta Plugin Row Meta |
|
833 | - * @param mixed $file Plugin Base file |
|
834 | - * @return array |
|
835 | - */ |
|
836 | - public function addLinksToPluginRowMeta($meta, $file) |
|
837 | - { |
|
838 | - if (EE_PLUGIN_BASENAME === $file) { |
|
839 | - $row_meta = [ |
|
840 | - 'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"' |
|
841 | - . ' aria-label="' |
|
842 | - . esc_attr__('View Event Espresso documentation', 'event_espresso') |
|
843 | - . '">' |
|
844 | - . esc_html__('Docs', 'event_espresso') |
|
845 | - . '</a>', |
|
846 | - 'api' => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"' |
|
847 | - . ' aria-label="' |
|
848 | - . esc_attr__('View Event Espresso API docs', 'event_espresso') |
|
849 | - . '">' |
|
850 | - . esc_html__('API docs', 'event_espresso') |
|
851 | - . '</a>', |
|
852 | - ]; |
|
853 | - return array_merge($meta, $row_meta); |
|
854 | - } |
|
855 | - return (array) $meta; |
|
856 | - } |
|
857 | - |
|
858 | - /**************************************************************************************/ |
|
859 | - /************************************* DEPRECATED *************************************/ |
|
860 | - /**************************************************************************************/ |
|
861 | - |
|
862 | - |
|
863 | - /** |
|
864 | - * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an |
|
865 | - * EE_Admin_Page route is called. |
|
866 | - * |
|
867 | - * @return void |
|
868 | - */ |
|
869 | - public function route_admin_request() |
|
870 | - { |
|
871 | - } |
|
872 | - |
|
873 | - |
|
874 | - /** |
|
875 | - * wp_loaded should fire on the WordPress wp_loaded hook. This fires on a VERY late priority. |
|
876 | - * |
|
877 | - * @return void |
|
878 | - */ |
|
879 | - public function wp_loaded() |
|
880 | - { |
|
881 | - } |
|
882 | - |
|
883 | - |
|
884 | - /** |
|
885 | - * static method for registering ee admin page. |
|
886 | - * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register. |
|
887 | - * |
|
888 | - * @param $page_basename |
|
889 | - * @param $page_path |
|
890 | - * @param array $config |
|
891 | - * @return void |
|
892 | - * @throws EE_Error |
|
893 | - * @see EE_Register_Admin_Page::register() |
|
894 | - * @since 4.3.0 |
|
895 | - * @deprecated 4.3.0 Use EE_Register_Admin_Page::register() instead |
|
896 | - */ |
|
897 | - public static function register_ee_admin_page($page_basename, $page_path, $config = []) |
|
898 | - { |
|
899 | - EE_Error::doing_it_wrong( |
|
900 | - __METHOD__, |
|
901 | - sprintf( |
|
902 | - esc_html__( |
|
903 | - 'Usage is deprecated. Use EE_Register_Admin_Page::register() for registering the %s admin page.', |
|
904 | - 'event_espresso' |
|
905 | - ), |
|
906 | - $page_basename |
|
907 | - ), |
|
908 | - '4.3' |
|
909 | - ); |
|
910 | - if (class_exists('EE_Register_Admin_Page')) { |
|
911 | - $config['page_path'] = $page_path; |
|
912 | - } |
|
913 | - EE_Register_Admin_Page::register($page_basename, $config); |
|
914 | - } |
|
915 | - |
|
916 | - |
|
917 | - /** |
|
918 | - * @param int $post_ID |
|
919 | - * @param \WP_Post $post |
|
920 | - * @return void |
|
921 | - * @deprecated 4.8.41 |
|
922 | - */ |
|
923 | - public static function parse_post_content_on_save($post_ID, $post) |
|
924 | - { |
|
925 | - EE_Error::doing_it_wrong( |
|
926 | - __METHOD__, |
|
927 | - esc_html__('Usage is deprecated', 'event_espresso'), |
|
928 | - '4.8.41' |
|
929 | - ); |
|
930 | - } |
|
931 | - |
|
932 | - |
|
933 | - /** |
|
934 | - * @param $option |
|
935 | - * @param $old_value |
|
936 | - * @param $value |
|
937 | - * @return void |
|
938 | - * @deprecated 4.8.41 |
|
939 | - */ |
|
940 | - public function reset_page_for_posts_on_change($option, $old_value, $value) |
|
941 | - { |
|
942 | - EE_Error::doing_it_wrong( |
|
943 | - __METHOD__, |
|
944 | - esc_html__('Usage is deprecated', 'event_espresso'), |
|
945 | - '4.8.41' |
|
946 | - ); |
|
947 | - } |
|
948 | - |
|
949 | - |
|
950 | - /** |
|
951 | - * @return void |
|
952 | - * @deprecated 4.9.27 |
|
953 | - */ |
|
954 | - public function get_persistent_admin_notices() |
|
955 | - { |
|
956 | - EE_Error::doing_it_wrong( |
|
957 | - __METHOD__, |
|
958 | - sprintf( |
|
959 | - esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
960 | - '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
961 | - ), |
|
962 | - '4.9.27' |
|
963 | - ); |
|
964 | - } |
|
965 | - |
|
966 | - |
|
967 | - /** |
|
968 | - * @throws InvalidInterfaceException |
|
969 | - * @throws InvalidDataTypeException |
|
970 | - * @throws DomainException |
|
971 | - * @deprecated 4.9.27 |
|
972 | - */ |
|
973 | - public function dismiss_ee_nag_notice_callback() |
|
974 | - { |
|
975 | - EE_Error::doing_it_wrong( |
|
976 | - __METHOD__, |
|
977 | - sprintf( |
|
978 | - esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
979 | - '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
980 | - ), |
|
981 | - '4.9.27' |
|
982 | - ); |
|
983 | - $this->persistent_admin_notice_manager->dismissNotice(); |
|
984 | - } |
|
985 | - |
|
986 | - |
|
987 | - /** |
|
988 | - * @return void |
|
989 | - * @deprecated 5.0.0.p |
|
990 | - */ |
|
991 | - public function enqueue_admin_scripts() |
|
992 | - { |
|
993 | - } |
|
994 | - |
|
995 | - |
|
996 | - |
|
997 | - /** |
|
998 | - * @return RequestInterface |
|
999 | - * @deprecated 5.0.0.p |
|
1000 | - */ |
|
1001 | - public function get_request() |
|
1002 | - { |
|
1003 | - EE_Error::doing_it_wrong( |
|
1004 | - __METHOD__, |
|
1005 | - sprintf( |
|
1006 | - esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
1007 | - 'EventEspresso\core\services\request\Request' |
|
1008 | - ), |
|
1009 | - '5.0.0.p' |
|
1010 | - ); |
|
1011 | - return $this->request; |
|
1012 | - } |
|
1013 | - |
|
1014 | - |
|
1015 | - /** |
|
1016 | - * @deprecated 5.0.0.p |
|
1017 | - */ |
|
1018 | - public function hookIntoWpPluginsPage() |
|
1019 | - { |
|
1020 | - } |
|
23 | + /** |
|
24 | + * @var EE_Admin $_instance |
|
25 | + */ |
|
26 | + private static $_instance; |
|
27 | + |
|
28 | + /** |
|
29 | + * @var PersistentAdminNoticeManager $persistent_admin_notice_manager |
|
30 | + */ |
|
31 | + private $persistent_admin_notice_manager; |
|
32 | + |
|
33 | + /** |
|
34 | + * @var LoaderInterface $loader |
|
35 | + */ |
|
36 | + protected $loader; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var RequestInterface |
|
40 | + */ |
|
41 | + protected $request; |
|
42 | + |
|
43 | + |
|
44 | + /** |
|
45 | + * @singleton method used to instantiate class object |
|
46 | + * @param LoaderInterface $loader |
|
47 | + * @param RequestInterface $request |
|
48 | + * @return EE_Admin |
|
49 | + * @throws EE_Error |
|
50 | + */ |
|
51 | + public static function instance(LoaderInterface $loader = null, RequestInterface $request = null) |
|
52 | + { |
|
53 | + // check if class object is instantiated |
|
54 | + if (! EE_Admin::$_instance instanceof EE_Admin) { |
|
55 | + EE_Admin::$_instance = new EE_Admin($loader, $request); |
|
56 | + } |
|
57 | + return EE_Admin::$_instance; |
|
58 | + } |
|
59 | + |
|
60 | + |
|
61 | + /** |
|
62 | + * @return EE_Admin |
|
63 | + * @throws EE_Error |
|
64 | + */ |
|
65 | + public static function reset() |
|
66 | + { |
|
67 | + EE_Admin::$_instance = null; |
|
68 | + $loader = LoaderFactory::getLoader(); |
|
69 | + $request = $loader->getShared('EventEspresso\core\services\request\Request'); |
|
70 | + return EE_Admin::instance($loader, $request); |
|
71 | + } |
|
72 | + |
|
73 | + |
|
74 | + /** |
|
75 | + * @param LoaderInterface $loader |
|
76 | + * @param RequestInterface $request |
|
77 | + * @throws EE_Error |
|
78 | + * @throws InvalidDataTypeException |
|
79 | + * @throws InvalidInterfaceException |
|
80 | + * @throws InvalidArgumentException |
|
81 | + */ |
|
82 | + protected function __construct(LoaderInterface $loader, RequestInterface $request) |
|
83 | + { |
|
84 | + $this->loader = $loader; |
|
85 | + $this->request = $request; |
|
86 | + // define global EE_Admin constants |
|
87 | + $this->_define_all_constants(); |
|
88 | + // set autoloaders for our admin page classes based on included path information |
|
89 | + EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN); |
|
90 | + // reset Environment config (we only do this on admin page loads); |
|
91 | + EE_Registry::instance()->CFG->environment->recheck_values(); |
|
92 | + // load EE_Request_Handler early |
|
93 | + add_action('AHEE__EE_System__initialize_last', [$this, 'init']); |
|
94 | + add_action('admin_init', [$this, 'admin_init'], 100); |
|
95 | + if (! $this->request->isAjax()) { |
|
96 | + // admin hooks |
|
97 | + add_action('admin_notices', [$this, 'display_admin_notices'], 10); |
|
98 | + add_action('network_admin_notices', [$this, 'display_admin_notices'], 10); |
|
99 | + add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2); |
|
100 | + add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2); |
|
101 | + add_filter('admin_footer_text', [$this, 'espresso_admin_footer']); |
|
102 | + add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2); |
|
103 | + add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2); |
|
104 | + } |
|
105 | + do_action('AHEE__EE_Admin__loaded'); |
|
106 | + } |
|
107 | + |
|
108 | + |
|
109 | + /** |
|
110 | + * _define_all_constants |
|
111 | + * define constants that are set globally for all admin pages |
|
112 | + * |
|
113 | + * @return void |
|
114 | + */ |
|
115 | + private function _define_all_constants() |
|
116 | + { |
|
117 | + if (! defined('EE_ADMIN_URL')) { |
|
118 | + define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/'); |
|
119 | + define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/'); |
|
120 | + define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/'); |
|
121 | + define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/'); |
|
122 | + define('WP_AJAX_URL', admin_url('admin-ajax.php')); |
|
123 | + } |
|
124 | + } |
|
125 | + |
|
126 | + |
|
127 | + /** |
|
128 | + * filter_plugin_actions - adds links to the Plugins page listing |
|
129 | + * |
|
130 | + * @param array $links |
|
131 | + * @param string $plugin |
|
132 | + * @return array |
|
133 | + */ |
|
134 | + public function filter_plugin_actions($links, $plugin) |
|
135 | + { |
|
136 | + // set $main_file in stone |
|
137 | + static $main_file; |
|
138 | + // if $main_file is not set yet |
|
139 | + if (! $main_file) { |
|
140 | + $main_file = EE_PLUGIN_BASENAME; |
|
141 | + } |
|
142 | + if ($plugin === $main_file) { |
|
143 | + // compare current plugin to this one |
|
144 | + if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) { |
|
145 | + $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"' |
|
146 | + . ' title="Event Espresso is in maintenance mode. Click this link to learn why.">' |
|
147 | + . esc_html__('Maintenance Mode Active', 'event_espresso') |
|
148 | + . '</a>'; |
|
149 | + array_unshift($links, $maintenance_link); |
|
150 | + } else { |
|
151 | + $org_settings_link = '<a href="admin.php?page=espresso_general_settings">' |
|
152 | + . esc_html__('Settings', 'event_espresso') |
|
153 | + . '</a>'; |
|
154 | + $events_link = '<a href="admin.php?page=espresso_events">' |
|
155 | + . esc_html__('Events', 'event_espresso') |
|
156 | + . '</a>'; |
|
157 | + // add before other links |
|
158 | + array_unshift($links, $org_settings_link, $events_link); |
|
159 | + } |
|
160 | + } |
|
161 | + return $links; |
|
162 | + } |
|
163 | + |
|
164 | + |
|
165 | + /** |
|
166 | + * hide_admin_pages_except_maintenance_mode |
|
167 | + * |
|
168 | + * @param array $admin_page_folder_names |
|
169 | + * @return array |
|
170 | + */ |
|
171 | + public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = []) |
|
172 | + { |
|
173 | + return [ |
|
174 | + 'maintenance' => EE_ADMIN_PAGES . 'maintenance/', |
|
175 | + 'about' => EE_ADMIN_PAGES . 'about/', |
|
176 | + 'support' => EE_ADMIN_PAGES . 'support/', |
|
177 | + ]; |
|
178 | + } |
|
179 | + |
|
180 | + |
|
181 | + /** |
|
182 | + * init- should fire after shortcode, module, addon, other plugin (default priority), and even |
|
183 | + * EE_Front_Controller's init phases have run |
|
184 | + * |
|
185 | + * @return void |
|
186 | + * @throws EE_Error |
|
187 | + * @throws InvalidArgumentException |
|
188 | + * @throws InvalidDataTypeException |
|
189 | + * @throws InvalidInterfaceException |
|
190 | + * @throws ReflectionException |
|
191 | + * @throws ServiceNotFoundException |
|
192 | + */ |
|
193 | + public function init() |
|
194 | + { |
|
195 | + // only enable most of the EE_Admin IF we're not in full maintenance mode |
|
196 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
197 | + $this->initModelsReady(); |
|
198 | + } |
|
199 | + // run the admin page factory but ONLY if: |
|
200 | + // - it is a regular non ajax admin request |
|
201 | + // - we are doing an ee admin ajax request |
|
202 | + if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) { |
|
203 | + try { |
|
204 | + // this loads the controller for the admin pages which will setup routing etc |
|
205 | + $admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]); |
|
206 | + /** @var EE_Admin_Page_Loader $admin_page_loader */ |
|
207 | + $admin_page_loader->init(); |
|
208 | + } catch (EE_Error $e) { |
|
209 | + $e->get_error(); |
|
210 | + } |
|
211 | + } |
|
212 | + if ($this->request->isAjax()) { |
|
213 | + return; |
|
214 | + } |
|
215 | + add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1); |
|
216 | + // make sure our CPTs and custom taxonomy metaboxes get shown for first time users |
|
217 | + add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10); |
|
218 | + add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10); |
|
219 | + // exclude EE critical pages from all nav menus and wp_list_pages |
|
220 | + add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10); |
|
221 | + } |
|
222 | + |
|
223 | + |
|
224 | + /** |
|
225 | + * Gets the loader (and if it wasn't previously set, sets it) |
|
226 | + * |
|
227 | + * @return LoaderInterface |
|
228 | + * @throws InvalidArgumentException |
|
229 | + * @throws InvalidDataTypeException |
|
230 | + * @throws InvalidInterfaceException |
|
231 | + */ |
|
232 | + protected function getLoader() |
|
233 | + { |
|
234 | + return $this->loader; |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * Method that's fired on admin requests (including admin ajax) but only when the models are usable |
|
240 | + * (ie, the site isn't in maintenance mode) |
|
241 | + * |
|
242 | + * @return void |
|
243 | + * @throws EE_Error |
|
244 | + * @since 4.9.63.p |
|
245 | + */ |
|
246 | + protected function initModelsReady() |
|
247 | + { |
|
248 | + // ok so we want to enable the entire admin |
|
249 | + $this->persistent_admin_notice_manager = $this->loader->getShared( |
|
250 | + 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
251 | + ); |
|
252 | + $this->persistent_admin_notice_manager->setReturnUrl( |
|
253 | + EE_Admin_Page::add_query_args_and_nonce( |
|
254 | + [ |
|
255 | + 'page' => $this->request->getRequestParam('page', ''), |
|
256 | + 'action' => $this->request->getRequestParam('action', ''), |
|
257 | + ], |
|
258 | + EE_ADMIN_URL |
|
259 | + ) |
|
260 | + ); |
|
261 | + $this->maybeSetDatetimeWarningNotice(); |
|
262 | + // at a glance dashboard widget |
|
263 | + add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10); |
|
264 | + // filter for get_edit_post_link used on comments for custom post types |
|
265 | + add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2); |
|
266 | + } |
|
267 | + |
|
268 | + |
|
269 | + /** |
|
270 | + * get_persistent_admin_notices |
|
271 | + * |
|
272 | + * @access public |
|
273 | + * @return void |
|
274 | + * @throws EE_Error |
|
275 | + * @throws InvalidArgumentException |
|
276 | + * @throws InvalidDataTypeException |
|
277 | + * @throws InvalidInterfaceException |
|
278 | + */ |
|
279 | + public function maybeSetDatetimeWarningNotice() |
|
280 | + { |
|
281 | + // add dismissible notice for datetime changes. Only valid if site does not have a timezone_string set. |
|
282 | + // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version |
|
283 | + // with this. But after enough time (indeterminate at this point) we can just remove this notice. |
|
284 | + // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626 |
|
285 | + if ( |
|
286 | + apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true) |
|
287 | + && ! get_option('timezone_string') |
|
288 | + && EEM_Event::instance()->count() > 0 |
|
289 | + ) { |
|
290 | + new PersistentAdminNotice( |
|
291 | + 'datetime_fix_notice', |
|
292 | + sprintf( |
|
293 | + esc_html__( |
|
294 | + '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times. Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.', |
|
295 | + 'event_espresso' |
|
296 | + ), |
|
297 | + '<strong>', |
|
298 | + '</strong>', |
|
299 | + '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">', |
|
300 | + '</a>', |
|
301 | + '<a href="' . EE_Admin_Page::add_query_args_and_nonce( |
|
302 | + [ |
|
303 | + 'page' => 'espresso_maintenance_settings', |
|
304 | + 'action' => 'datetime_tools', |
|
305 | + ], |
|
306 | + admin_url('admin.php') |
|
307 | + ) . '">' |
|
308 | + ), |
|
309 | + false, |
|
310 | + 'manage_options', |
|
311 | + 'datetime_fix_persistent_notice' |
|
312 | + ); |
|
313 | + } |
|
314 | + } |
|
315 | + |
|
316 | + |
|
317 | + /** |
|
318 | + * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from |
|
319 | + * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in |
|
320 | + * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that |
|
321 | + * to override any queries found in the existing query for the given post type. Note that _default_query is not a |
|
322 | + * normal property on the post_type object. It's found ONLY in this particular context. |
|
323 | + * |
|
324 | + * @param WP_Post $post_type WP post type object |
|
325 | + * @return WP_Post |
|
326 | + * @throws InvalidArgumentException |
|
327 | + * @throws InvalidDataTypeException |
|
328 | + * @throws InvalidInterfaceException |
|
329 | + */ |
|
330 | + public function remove_pages_from_nav_menu($post_type) |
|
331 | + { |
|
332 | + // if this isn't the "pages" post type let's get out |
|
333 | + if ($post_type->name !== 'page') { |
|
334 | + return $post_type; |
|
335 | + } |
|
336 | + $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array(); |
|
337 | + $post_type->_default_query = [ |
|
338 | + 'post__not_in' => $critical_pages, |
|
339 | + ]; |
|
340 | + return $post_type; |
|
341 | + } |
|
342 | + |
|
343 | + |
|
344 | + /** |
|
345 | + * WP by default only shows three metaboxes in "nav-menus.php" for first times users. |
|
346 | + * We want to make sure our metaboxes get shown as well |
|
347 | + * |
|
348 | + * @return void |
|
349 | + */ |
|
350 | + public function enable_hidden_ee_nav_menu_metaboxes() |
|
351 | + { |
|
352 | + global $wp_meta_boxes, $pagenow; |
|
353 | + if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') { |
|
354 | + return; |
|
355 | + } |
|
356 | + $user = wp_get_current_user(); |
|
357 | + // has this been done yet? |
|
358 | + if (get_user_option('ee_nav_menu_initialized', $user->ID)) { |
|
359 | + return; |
|
360 | + } |
|
361 | + |
|
362 | + $hidden_meta_boxes = get_user_option('metaboxhidden_nav-menus', $user->ID); |
|
363 | + $initial_meta_boxes = apply_filters( |
|
364 | + 'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes', |
|
365 | + [ |
|
366 | + 'nav-menu-theme-locations', |
|
367 | + 'add-page', |
|
368 | + 'add-custom-links', |
|
369 | + 'add-category', |
|
370 | + 'add-espresso_events', |
|
371 | + 'add-espresso_venues', |
|
372 | + 'add-espresso_event_categories', |
|
373 | + 'add-espresso_venue_categories', |
|
374 | + 'add-post-type-post', |
|
375 | + 'add-post-type-page', |
|
376 | + ] |
|
377 | + ); |
|
378 | + |
|
379 | + if (is_array($hidden_meta_boxes)) { |
|
380 | + foreach ($hidden_meta_boxes as $key => $meta_box_id) { |
|
381 | + if (in_array($meta_box_id, $initial_meta_boxes, true)) { |
|
382 | + unset($hidden_meta_boxes[ $key ]); |
|
383 | + } |
|
384 | + } |
|
385 | + } |
|
386 | + update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true); |
|
387 | + update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true); |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + /** |
|
392 | + * This method simply registers custom nav menu boxes for "nav_menus.php route" |
|
393 | + * Currently EE is using this to make sure there are menu options for our CPT archive page routes. |
|
394 | + * |
|
395 | + * @return void |
|
396 | + * @todo modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by |
|
397 | + * addons etc. |
|
398 | + */ |
|
399 | + public function register_custom_nav_menu_boxes() |
|
400 | + { |
|
401 | + add_meta_box( |
|
402 | + 'add-extra-nav-menu-pages', |
|
403 | + esc_html__('Event Espresso Pages', 'event_espresso'), |
|
404 | + [$this, 'ee_cpt_archive_pages'], |
|
405 | + 'nav-menus', |
|
406 | + 'side', |
|
407 | + 'core' |
|
408 | + ); |
|
409 | + add_filter( |
|
410 | + "postbox_classes_nav-menus_add-extra-nav-menu-pages", |
|
411 | + function ($classes) { |
|
412 | + array_push($classes, 'ee-admin-container'); |
|
413 | + return $classes; |
|
414 | + } |
|
415 | + ); |
|
416 | + } |
|
417 | + |
|
418 | + |
|
419 | + /** |
|
420 | + * Use this to edit the post link for our cpts so that the edit link points to the correct page. |
|
421 | + * |
|
422 | + * @param string $link the original link generated by wp |
|
423 | + * @param int $id post id |
|
424 | + * @return string the (maybe) modified link |
|
425 | + * @since 4.3.0 |
|
426 | + */ |
|
427 | + public function modify_edit_post_link($link, $id) |
|
428 | + { |
|
429 | + if (! $post = get_post($id)) { |
|
430 | + return $link; |
|
431 | + } |
|
432 | + if ($post->post_type === 'espresso_attendees') { |
|
433 | + $query_args = [ |
|
434 | + 'action' => 'edit_attendee', |
|
435 | + 'post' => $id, |
|
436 | + ]; |
|
437 | + return EEH_URL::add_query_args_and_nonce( |
|
438 | + $query_args, |
|
439 | + admin_url('admin.php?page=espresso_registrations') |
|
440 | + ); |
|
441 | + } |
|
442 | + return $link; |
|
443 | + } |
|
444 | + |
|
445 | + |
|
446 | + public function ee_cpt_archive_pages() |
|
447 | + { |
|
448 | + global $nav_menu_selected_id; |
|
449 | + $removed_args = [ |
|
450 | + 'action', |
|
451 | + 'customlink-tab', |
|
452 | + 'edit-menu-item', |
|
453 | + 'menu-item', |
|
454 | + 'page-tab', |
|
455 | + '_wpnonce', |
|
456 | + ]; |
|
457 | + $nav_tab_link = $nav_menu_selected_id |
|
458 | + ? esc_url( |
|
459 | + add_query_arg( |
|
460 | + 'extra-nav-menu-pages-tab', |
|
461 | + 'event-archives', |
|
462 | + remove_query_arg($removed_args) |
|
463 | + ) |
|
464 | + ) |
|
465 | + : ''; |
|
466 | + $select_all_link = esc_url( |
|
467 | + add_query_arg( |
|
468 | + [ |
|
469 | + 'extra-nav-menu-pages-tab' => 'event-archives', |
|
470 | + 'selectall' => 1, |
|
471 | + ], |
|
472 | + remove_query_arg($removed_args) |
|
473 | + ) |
|
474 | + ); |
|
475 | + $pages = $this->_get_extra_nav_menu_pages_items(); |
|
476 | + $args['walker'] = new Walker_Nav_Menu_Checklist(false); |
|
477 | + ; |
|
478 | + $nav_menu_pages_items = walk_nav_menu_tree( |
|
479 | + array_map( |
|
480 | + [$this, '_setup_extra_nav_menu_pages_items'], |
|
481 | + $pages |
|
482 | + ), |
|
483 | + 0, |
|
484 | + (object) $args |
|
485 | + ); |
|
486 | + EEH_Template::display_template( |
|
487 | + EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php', |
|
488 | + [ |
|
489 | + 'nav_menu_selected_id' => $nav_menu_selected_id, |
|
490 | + 'nav_menu_pages_items' => $nav_menu_pages_items, |
|
491 | + 'nav_tab_link' => $nav_tab_link, |
|
492 | + 'select_all_link' => $select_all_link, |
|
493 | + ] |
|
494 | + ); |
|
495 | + } |
|
496 | + |
|
497 | + |
|
498 | + /** |
|
499 | + * Returns an array of event archive nav items. |
|
500 | + * |
|
501 | + * @return array |
|
502 | + * @todo for now this method is just in place so when it gets abstracted further we can substitute in whatever |
|
503 | + * method we use for getting the extra nav menu items |
|
504 | + */ |
|
505 | + private function _get_extra_nav_menu_pages_items() |
|
506 | + { |
|
507 | + $menuitems[] = [ |
|
508 | + 'title' => esc_html__('Event List', 'event_espresso'), |
|
509 | + 'url' => get_post_type_archive_link('espresso_events'), |
|
510 | + 'description' => esc_html__('Archive page for all events.', 'event_espresso'), |
|
511 | + ]; |
|
512 | + return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems); |
|
513 | + } |
|
514 | + |
|
515 | + |
|
516 | + /** |
|
517 | + * Setup nav menu walker item for usage in the event archive nav menu metabox. It receives a menu_item array with |
|
518 | + * the properties and converts it to the menu item object. |
|
519 | + * |
|
520 | + * @param $menu_item_values |
|
521 | + * @return stdClass |
|
522 | + * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php |
|
523 | + */ |
|
524 | + private function _setup_extra_nav_menu_pages_items($menu_item_values) |
|
525 | + { |
|
526 | + $menu_item = new stdClass(); |
|
527 | + $keys = [ |
|
528 | + 'ID' => 0, |
|
529 | + 'db_id' => 0, |
|
530 | + 'menu_item_parent' => 0, |
|
531 | + 'object_id' => -1, |
|
532 | + 'post_parent' => 0, |
|
533 | + 'type' => 'custom', |
|
534 | + 'object' => '', |
|
535 | + 'type_label' => esc_html__('Extra Nav Menu Item', 'event_espresso'), |
|
536 | + 'title' => '', |
|
537 | + 'url' => '', |
|
538 | + 'target' => '', |
|
539 | + 'attr_title' => '', |
|
540 | + 'description' => '', |
|
541 | + 'classes' => [], |
|
542 | + 'xfn' => '', |
|
543 | + ]; |
|
544 | + foreach ($keys as $key => $value) { |
|
545 | + $menu_item->{$key} = $menu_item_values[ $key ] ?? $value; |
|
546 | + } |
|
547 | + return $menu_item; |
|
548 | + } |
|
549 | + |
|
550 | + |
|
551 | + /** |
|
552 | + * admin_init |
|
553 | + * |
|
554 | + * @return void |
|
555 | + * @throws InvalidArgumentException |
|
556 | + * @throws InvalidDataTypeException |
|
557 | + * @throws InvalidInterfaceException |
|
558 | + */ |
|
559 | + public function admin_init() |
|
560 | + { |
|
561 | + /** |
|
562 | + * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php), |
|
563 | + * so any hooking into core WP routes is taken care of. So in this next few lines of code: |
|
564 | + * - check if doing post processing. |
|
565 | + * - check if doing post processing of one of EE CPTs |
|
566 | + * - instantiate the corresponding EE CPT model for the post_type being processed. |
|
567 | + */ |
|
568 | + $action = $this->request->getRequestParam('action'); |
|
569 | + $post_type = $this->request->getRequestParam('post_type'); |
|
570 | + if ($post_type && $action === 'editpost') { |
|
571 | + /** @var CustomPostTypeDefinitions $custom_post_types */ |
|
572 | + $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class); |
|
573 | + $custom_post_types->getCustomPostTypeModels($post_type); |
|
574 | + } |
|
575 | + |
|
576 | + |
|
577 | + if (! $this->request->isAjax()) { |
|
578 | + /** |
|
579 | + * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting |
|
580 | + * critical pages. The only place critical pages need included in a generated dropdown is on the "Critical |
|
581 | + * Pages" tab in the EE General Settings Admin page. |
|
582 | + * This is for user-proofing. |
|
583 | + */ |
|
584 | + add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']); |
|
585 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
586 | + $this->adminInitModelsReady(); |
|
587 | + } |
|
588 | + } |
|
589 | + } |
|
590 | + |
|
591 | + |
|
592 | + /** |
|
593 | + * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode) |
|
594 | + */ |
|
595 | + protected function adminInitModelsReady() |
|
596 | + { |
|
597 | + if (function_exists('wp_add_privacy_policy_content')) { |
|
598 | + $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager'); |
|
599 | + } |
|
600 | + } |
|
601 | + |
|
602 | + |
|
603 | + /** |
|
604 | + * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection. |
|
605 | + * |
|
606 | + * @param string $output Current output. |
|
607 | + * @return string |
|
608 | + * @throws InvalidArgumentException |
|
609 | + * @throws InvalidDataTypeException |
|
610 | + * @throws InvalidInterfaceException |
|
611 | + */ |
|
612 | + public function modify_dropdown_pages($output) |
|
613 | + { |
|
614 | + // get critical pages |
|
615 | + $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array(); |
|
616 | + |
|
617 | + // split current output by line break for easier parsing. |
|
618 | + $split_output = explode("\n", $output); |
|
619 | + |
|
620 | + // loop through to remove any critical pages from the array. |
|
621 | + foreach ($critical_pages as $page_id) { |
|
622 | + $needle = 'value="' . $page_id . '"'; |
|
623 | + foreach ($split_output as $key => $haystack) { |
|
624 | + if (strpos($haystack, $needle) !== false) { |
|
625 | + unset($split_output[ $key ]); |
|
626 | + } |
|
627 | + } |
|
628 | + } |
|
629 | + // replace output with the new contents |
|
630 | + return implode("\n", $split_output); |
|
631 | + } |
|
632 | + |
|
633 | + |
|
634 | + /** |
|
635 | + * display_admin_notices |
|
636 | + * |
|
637 | + * @return void |
|
638 | + */ |
|
639 | + public function display_admin_notices() |
|
640 | + { |
|
641 | + echo EE_Error::get_notices(); // already escaped |
|
642 | + } |
|
643 | + |
|
644 | + |
|
645 | + /** |
|
646 | + * @param array $elements |
|
647 | + * @return array |
|
648 | + * @throws EE_Error |
|
649 | + * @throws InvalidArgumentException |
|
650 | + * @throws InvalidDataTypeException |
|
651 | + * @throws InvalidInterfaceException |
|
652 | + */ |
|
653 | + public function dashboard_glance_items($elements) |
|
654 | + { |
|
655 | + $elements = is_array($elements) ? $elements : [$elements]; |
|
656 | + $events = EEM_Event::instance()->count(); |
|
657 | + $items['events']['url'] = EE_Admin_Page::add_query_args_and_nonce( |
|
658 | + ['page' => 'espresso_events'], |
|
659 | + admin_url('admin.php') |
|
660 | + ); |
|
661 | + $items['events']['text'] = sprintf( |
|
662 | + esc_html( |
|
663 | + _n('%s Event', '%s Events', $events, 'event_espresso') |
|
664 | + ), |
|
665 | + number_format_i18n($events) |
|
666 | + ); |
|
667 | + $items['events']['title'] = esc_html__('Click to view all Events', 'event_espresso'); |
|
668 | + $registrations = EEM_Registration::instance()->count( |
|
669 | + [ |
|
670 | + [ |
|
671 | + 'STS_ID' => ['!=', EEM_Registration::status_id_incomplete], |
|
672 | + ], |
|
673 | + ] |
|
674 | + ); |
|
675 | + $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce( |
|
676 | + ['page' => 'espresso_registrations'], |
|
677 | + admin_url('admin.php') |
|
678 | + ); |
|
679 | + $items['registrations']['text'] = sprintf( |
|
680 | + esc_html( |
|
681 | + _n('%s Registration', '%s Registrations', $registrations, 'event_espresso') |
|
682 | + ), |
|
683 | + number_format_i18n($registrations) |
|
684 | + ); |
|
685 | + $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso'); |
|
686 | + |
|
687 | + $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items); |
|
688 | + |
|
689 | + foreach ($items as $type => $item_properties) { |
|
690 | + $elements[] = sprintf( |
|
691 | + '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>', |
|
692 | + $item_properties['url'], |
|
693 | + $item_properties['title'], |
|
694 | + $item_properties['text'] |
|
695 | + ); |
|
696 | + } |
|
697 | + return $elements; |
|
698 | + } |
|
699 | + |
|
700 | + |
|
701 | + /** |
|
702 | + * check_for_invalid_datetime_formats |
|
703 | + * if an admin changes their date or time format settings on the WP General Settings admin page, verify that |
|
704 | + * their selected format can be parsed by PHP |
|
705 | + * |
|
706 | + * @param $value |
|
707 | + * @param $option |
|
708 | + * @return string |
|
709 | + */ |
|
710 | + public function check_for_invalid_datetime_formats($value, $option) |
|
711 | + { |
|
712 | + // check for date_format or time_format |
|
713 | + switch ($option) { |
|
714 | + case 'date_format': |
|
715 | + $date_time_format = $value . ' ' . get_option('time_format'); |
|
716 | + break; |
|
717 | + case 'time_format': |
|
718 | + $date_time_format = get_option('date_format') . ' ' . $value; |
|
719 | + break; |
|
720 | + default: |
|
721 | + $date_time_format = false; |
|
722 | + } |
|
723 | + // do we have a date_time format to check ? |
|
724 | + if ($date_time_format) { |
|
725 | + $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format); |
|
726 | + |
|
727 | + if (is_array($error_msg)) { |
|
728 | + $msg = '<p>' |
|
729 | + . sprintf( |
|
730 | + esc_html__( |
|
731 | + 'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:', |
|
732 | + 'event_espresso' |
|
733 | + ), |
|
734 | + date($date_time_format), |
|
735 | + $date_time_format |
|
736 | + ) |
|
737 | + . '</p><p><ul>'; |
|
738 | + |
|
739 | + |
|
740 | + foreach ($error_msg as $error) { |
|
741 | + $msg .= '<li>' . $error . '</li>'; |
|
742 | + } |
|
743 | + |
|
744 | + $msg .= '</ul></p><p>' |
|
745 | + . sprintf( |
|
746 | + esc_html__( |
|
747 | + '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s', |
|
748 | + 'event_espresso' |
|
749 | + ), |
|
750 | + '<span style="color:#D54E21;">', |
|
751 | + '</span>' |
|
752 | + ) |
|
753 | + . '</p>'; |
|
754 | + |
|
755 | + // trigger WP settings error |
|
756 | + add_settings_error( |
|
757 | + 'date_format', |
|
758 | + 'date_format', |
|
759 | + $msg |
|
760 | + ); |
|
761 | + |
|
762 | + // set format to something valid |
|
763 | + switch ($option) { |
|
764 | + case 'date_format': |
|
765 | + $value = 'F j, Y'; |
|
766 | + break; |
|
767 | + case 'time_format': |
|
768 | + $value = 'g:i a'; |
|
769 | + break; |
|
770 | + } |
|
771 | + } |
|
772 | + } |
|
773 | + return $value; |
|
774 | + } |
|
775 | + |
|
776 | + |
|
777 | + /** |
|
778 | + * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso" |
|
779 | + * |
|
780 | + * @param $content |
|
781 | + * @return string |
|
782 | + */ |
|
783 | + public function its_eSpresso($content) |
|
784 | + { |
|
785 | + return str_replace('[EXPRESSO_', '[ESPRESSO_', $content); |
|
786 | + } |
|
787 | + |
|
788 | + |
|
789 | + /** |
|
790 | + * espresso_admin_footer |
|
791 | + * |
|
792 | + * @return string |
|
793 | + */ |
|
794 | + public function espresso_admin_footer() |
|
795 | + { |
|
796 | + return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']); |
|
797 | + } |
|
798 | + |
|
799 | + |
|
800 | + /** |
|
801 | + * Hooks into the "post states" filter in a wp post type list table. |
|
802 | + * |
|
803 | + * @param array $post_states |
|
804 | + * @param WP_Post $post |
|
805 | + * @return array |
|
806 | + * @throws InvalidArgumentException |
|
807 | + * @throws InvalidDataTypeException |
|
808 | + * @throws InvalidInterfaceException |
|
809 | + */ |
|
810 | + public function displayStateForCriticalPages($post_states, $post) |
|
811 | + { |
|
812 | + $post_states = (array) $post_states; |
|
813 | + if (! $post instanceof WP_Post || $post->post_type !== 'page') { |
|
814 | + return $post_states; |
|
815 | + } |
|
816 | + /** @var EE_Core_Config $config */ |
|
817 | + $config = $this->loader->getShared('EE_Config')->core; |
|
818 | + if (in_array($post->ID, $config->get_critical_pages_array(), true)) { |
|
819 | + $post_states[] = sprintf( |
|
820 | + /* Translators: Using company name - Event Espresso Critical Page */ |
|
821 | + esc_html__('%s Critical Page', 'event_espresso'), |
|
822 | + 'Event Espresso' |
|
823 | + ); |
|
824 | + } |
|
825 | + return $post_states; |
|
826 | + } |
|
827 | + |
|
828 | + |
|
829 | + /** |
|
830 | + * Show documentation links on the plugins page |
|
831 | + * |
|
832 | + * @param mixed $meta Plugin Row Meta |
|
833 | + * @param mixed $file Plugin Base file |
|
834 | + * @return array |
|
835 | + */ |
|
836 | + public function addLinksToPluginRowMeta($meta, $file) |
|
837 | + { |
|
838 | + if (EE_PLUGIN_BASENAME === $file) { |
|
839 | + $row_meta = [ |
|
840 | + 'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"' |
|
841 | + . ' aria-label="' |
|
842 | + . esc_attr__('View Event Espresso documentation', 'event_espresso') |
|
843 | + . '">' |
|
844 | + . esc_html__('Docs', 'event_espresso') |
|
845 | + . '</a>', |
|
846 | + 'api' => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"' |
|
847 | + . ' aria-label="' |
|
848 | + . esc_attr__('View Event Espresso API docs', 'event_espresso') |
|
849 | + . '">' |
|
850 | + . esc_html__('API docs', 'event_espresso') |
|
851 | + . '</a>', |
|
852 | + ]; |
|
853 | + return array_merge($meta, $row_meta); |
|
854 | + } |
|
855 | + return (array) $meta; |
|
856 | + } |
|
857 | + |
|
858 | + /**************************************************************************************/ |
|
859 | + /************************************* DEPRECATED *************************************/ |
|
860 | + /**************************************************************************************/ |
|
861 | + |
|
862 | + |
|
863 | + /** |
|
864 | + * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an |
|
865 | + * EE_Admin_Page route is called. |
|
866 | + * |
|
867 | + * @return void |
|
868 | + */ |
|
869 | + public function route_admin_request() |
|
870 | + { |
|
871 | + } |
|
872 | + |
|
873 | + |
|
874 | + /** |
|
875 | + * wp_loaded should fire on the WordPress wp_loaded hook. This fires on a VERY late priority. |
|
876 | + * |
|
877 | + * @return void |
|
878 | + */ |
|
879 | + public function wp_loaded() |
|
880 | + { |
|
881 | + } |
|
882 | + |
|
883 | + |
|
884 | + /** |
|
885 | + * static method for registering ee admin page. |
|
886 | + * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register. |
|
887 | + * |
|
888 | + * @param $page_basename |
|
889 | + * @param $page_path |
|
890 | + * @param array $config |
|
891 | + * @return void |
|
892 | + * @throws EE_Error |
|
893 | + * @see EE_Register_Admin_Page::register() |
|
894 | + * @since 4.3.0 |
|
895 | + * @deprecated 4.3.0 Use EE_Register_Admin_Page::register() instead |
|
896 | + */ |
|
897 | + public static function register_ee_admin_page($page_basename, $page_path, $config = []) |
|
898 | + { |
|
899 | + EE_Error::doing_it_wrong( |
|
900 | + __METHOD__, |
|
901 | + sprintf( |
|
902 | + esc_html__( |
|
903 | + 'Usage is deprecated. Use EE_Register_Admin_Page::register() for registering the %s admin page.', |
|
904 | + 'event_espresso' |
|
905 | + ), |
|
906 | + $page_basename |
|
907 | + ), |
|
908 | + '4.3' |
|
909 | + ); |
|
910 | + if (class_exists('EE_Register_Admin_Page')) { |
|
911 | + $config['page_path'] = $page_path; |
|
912 | + } |
|
913 | + EE_Register_Admin_Page::register($page_basename, $config); |
|
914 | + } |
|
915 | + |
|
916 | + |
|
917 | + /** |
|
918 | + * @param int $post_ID |
|
919 | + * @param \WP_Post $post |
|
920 | + * @return void |
|
921 | + * @deprecated 4.8.41 |
|
922 | + */ |
|
923 | + public static function parse_post_content_on_save($post_ID, $post) |
|
924 | + { |
|
925 | + EE_Error::doing_it_wrong( |
|
926 | + __METHOD__, |
|
927 | + esc_html__('Usage is deprecated', 'event_espresso'), |
|
928 | + '4.8.41' |
|
929 | + ); |
|
930 | + } |
|
931 | + |
|
932 | + |
|
933 | + /** |
|
934 | + * @param $option |
|
935 | + * @param $old_value |
|
936 | + * @param $value |
|
937 | + * @return void |
|
938 | + * @deprecated 4.8.41 |
|
939 | + */ |
|
940 | + public function reset_page_for_posts_on_change($option, $old_value, $value) |
|
941 | + { |
|
942 | + EE_Error::doing_it_wrong( |
|
943 | + __METHOD__, |
|
944 | + esc_html__('Usage is deprecated', 'event_espresso'), |
|
945 | + '4.8.41' |
|
946 | + ); |
|
947 | + } |
|
948 | + |
|
949 | + |
|
950 | + /** |
|
951 | + * @return void |
|
952 | + * @deprecated 4.9.27 |
|
953 | + */ |
|
954 | + public function get_persistent_admin_notices() |
|
955 | + { |
|
956 | + EE_Error::doing_it_wrong( |
|
957 | + __METHOD__, |
|
958 | + sprintf( |
|
959 | + esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
960 | + '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
961 | + ), |
|
962 | + '4.9.27' |
|
963 | + ); |
|
964 | + } |
|
965 | + |
|
966 | + |
|
967 | + /** |
|
968 | + * @throws InvalidInterfaceException |
|
969 | + * @throws InvalidDataTypeException |
|
970 | + * @throws DomainException |
|
971 | + * @deprecated 4.9.27 |
|
972 | + */ |
|
973 | + public function dismiss_ee_nag_notice_callback() |
|
974 | + { |
|
975 | + EE_Error::doing_it_wrong( |
|
976 | + __METHOD__, |
|
977 | + sprintf( |
|
978 | + esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
979 | + '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
980 | + ), |
|
981 | + '4.9.27' |
|
982 | + ); |
|
983 | + $this->persistent_admin_notice_manager->dismissNotice(); |
|
984 | + } |
|
985 | + |
|
986 | + |
|
987 | + /** |
|
988 | + * @return void |
|
989 | + * @deprecated 5.0.0.p |
|
990 | + */ |
|
991 | + public function enqueue_admin_scripts() |
|
992 | + { |
|
993 | + } |
|
994 | + |
|
995 | + |
|
996 | + |
|
997 | + /** |
|
998 | + * @return RequestInterface |
|
999 | + * @deprecated 5.0.0.p |
|
1000 | + */ |
|
1001 | + public function get_request() |
|
1002 | + { |
|
1003 | + EE_Error::doing_it_wrong( |
|
1004 | + __METHOD__, |
|
1005 | + sprintf( |
|
1006 | + esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'), |
|
1007 | + 'EventEspresso\core\services\request\Request' |
|
1008 | + ), |
|
1009 | + '5.0.0.p' |
|
1010 | + ); |
|
1011 | + return $this->request; |
|
1012 | + } |
|
1013 | + |
|
1014 | + |
|
1015 | + /** |
|
1016 | + * @deprecated 5.0.0.p |
|
1017 | + */ |
|
1018 | + public function hookIntoWpPluginsPage() |
|
1019 | + { |
|
1020 | + } |
|
1021 | 1021 | } |
@@ -5,7 +5,7 @@ discard block |
||
5 | 5 | use EventEspresso\core\services\request\sanitizers\AllowedTags; |
6 | 6 | |
7 | 7 | if (! class_exists('WP_List_Table')) { |
8 | - require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; |
|
8 | + require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; |
|
9 | 9 | } |
10 | 10 | |
11 | 11 | |
@@ -23,928 +23,928 @@ discard block |
||
23 | 23 | */ |
24 | 24 | abstract class EE_Admin_List_Table extends WP_List_Table |
25 | 25 | { |
26 | - const ACTION_COPY = 'duplicate'; |
|
27 | - |
|
28 | - const ACTION_DELETE = 'delete'; |
|
29 | - |
|
30 | - const ACTION_EDIT = 'edit'; |
|
31 | - |
|
32 | - const ACTION_RESTORE = 'restore'; |
|
33 | - |
|
34 | - const ACTION_TRASH = 'trash'; |
|
35 | - |
|
36 | - protected static $actions = [ |
|
37 | - self::ACTION_COPY, |
|
38 | - self::ACTION_DELETE, |
|
39 | - self::ACTION_EDIT, |
|
40 | - self::ACTION_RESTORE, |
|
41 | - self::ACTION_TRASH, |
|
42 | - ]; |
|
43 | - |
|
44 | - /** |
|
45 | - * holds the data that will be processed for the table |
|
46 | - * |
|
47 | - * @var array $_data |
|
48 | - */ |
|
49 | - protected $_data; |
|
50 | - |
|
51 | - |
|
52 | - /** |
|
53 | - * This holds the value of all the data available for the given view (for all pages). |
|
54 | - * |
|
55 | - * @var int $_all_data_count |
|
56 | - */ |
|
57 | - protected $_all_data_count; |
|
58 | - |
|
59 | - |
|
60 | - /** |
|
61 | - * Will contain the count of trashed items for the view label. |
|
62 | - * |
|
63 | - * @var int $_trashed_count |
|
64 | - */ |
|
65 | - protected $_trashed_count; |
|
66 | - |
|
67 | - |
|
68 | - /** |
|
69 | - * This is what will be referenced as the slug for the current screen |
|
70 | - * |
|
71 | - * @var string $_screen |
|
72 | - */ |
|
73 | - protected $_screen; |
|
74 | - |
|
75 | - |
|
76 | - /** |
|
77 | - * this is the EE_Admin_Page object |
|
78 | - * |
|
79 | - * @var EE_Admin_Page $_admin_page |
|
80 | - */ |
|
81 | - protected $_admin_page; |
|
82 | - |
|
83 | - |
|
84 | - /** |
|
85 | - * The current view |
|
86 | - * |
|
87 | - * @var string $_view |
|
88 | - */ |
|
89 | - protected $_view; |
|
90 | - |
|
91 | - |
|
92 | - /** |
|
93 | - * array of possible views for this table |
|
94 | - * |
|
95 | - * @var array $_views |
|
96 | - */ |
|
97 | - protected $_views; |
|
98 | - |
|
99 | - |
|
100 | - /** |
|
101 | - * An array of key => value pairs containing information about the current table |
|
102 | - * array( |
|
103 | - * 'plural' => 'plural label', |
|
104 | - * 'singular' => 'singular label', |
|
105 | - * 'ajax' => false, //whether to use ajax or not |
|
106 | - * 'screen' => null, //string used to reference what screen this is |
|
107 | - * (WP_List_table converts to screen object) |
|
108 | - * ) |
|
109 | - * |
|
110 | - * @var array $_wp_list_args |
|
111 | - */ |
|
112 | - protected $_wp_list_args; |
|
113 | - |
|
114 | - /** |
|
115 | - * an array of column names |
|
116 | - * array( |
|
117 | - * 'internal-name' => 'Title' |
|
118 | - * ) |
|
119 | - * |
|
120 | - * @var array $_columns |
|
121 | - */ |
|
122 | - protected $_columns; |
|
123 | - |
|
124 | - /** |
|
125 | - * An array of sortable columns |
|
126 | - * array( |
|
127 | - * 'internal-name' => 'orderby' //or |
|
128 | - * 'internal-name' => array( 'orderby', true ) |
|
129 | - * ) |
|
130 | - * |
|
131 | - * @var array $_sortable_columns |
|
132 | - */ |
|
133 | - protected $_sortable_columns; |
|
134 | - |
|
135 | - /** |
|
136 | - * callback method used to perform AJAX row reordering |
|
137 | - * |
|
138 | - * @var string $_ajax_sorting_callback |
|
139 | - */ |
|
140 | - protected $_ajax_sorting_callback; |
|
141 | - |
|
142 | - /** |
|
143 | - * An array of hidden columns (if needed) |
|
144 | - * array('internal-name', 'internal-name') |
|
145 | - * |
|
146 | - * @var array $_hidden_columns |
|
147 | - */ |
|
148 | - protected $_hidden_columns; |
|
149 | - |
|
150 | - /** |
|
151 | - * holds the per_page value |
|
152 | - * |
|
153 | - * @var int $_per_page |
|
154 | - */ |
|
155 | - protected $_per_page; |
|
156 | - |
|
157 | - /** |
|
158 | - * holds what page number is currently being viewed |
|
159 | - * |
|
160 | - * @var int $_current_page |
|
161 | - */ |
|
162 | - protected $_current_page; |
|
163 | - |
|
164 | - /** |
|
165 | - * the reference string for the nonce_action |
|
166 | - * |
|
167 | - * @var string $_nonce_action_ref |
|
168 | - */ |
|
169 | - protected $_nonce_action_ref; |
|
170 | - |
|
171 | - /** |
|
172 | - * property to hold incoming request data (as set by the admin_page_core) |
|
173 | - * |
|
174 | - * @var array $_req_data |
|
175 | - */ |
|
176 | - protected $_req_data; |
|
177 | - |
|
178 | - |
|
179 | - /** |
|
180 | - * yes / no array for admin form fields |
|
181 | - * |
|
182 | - * @var array $_yes_no |
|
183 | - */ |
|
184 | - protected $_yes_no = []; |
|
185 | - |
|
186 | - /** |
|
187 | - * Array describing buttons that should appear at the bottom of the page |
|
188 | - * Keys are strings that represent the button's function (specifically a key in _labels['buttons']), |
|
189 | - * and the values are another array with the following keys |
|
190 | - * array( |
|
191 | - * 'route' => 'page_route', |
|
192 | - * 'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button. |
|
193 | - * ) |
|
194 | - * |
|
195 | - * @var array $_bottom_buttons |
|
196 | - */ |
|
197 | - protected $_bottom_buttons = []; |
|
198 | - |
|
199 | - |
|
200 | - /** |
|
201 | - * Used to indicate what should be the primary column for the list table. |
|
202 | - * If not present then falls back to what WP calculates |
|
203 | - * as the primary column. |
|
204 | - * |
|
205 | - * @type string $_primary_column |
|
206 | - */ |
|
207 | - protected $_primary_column = ''; |
|
208 | - |
|
209 | - |
|
210 | - /** |
|
211 | - * Used to indicate whether the table has a checkbox column or not. |
|
212 | - * |
|
213 | - * @type bool $_has_checkbox_column |
|
214 | - */ |
|
215 | - protected $_has_checkbox_column = false; |
|
216 | - |
|
217 | - /** |
|
218 | - * @var AdminListTableFilters|null |
|
219 | - */ |
|
220 | - protected ?AdminListTableFilters $admin_list_table_filters = null; |
|
221 | - |
|
222 | - |
|
223 | - /** |
|
224 | - * @param EE_Admin_Page $admin_page we use this for obtaining everything we need in the list table |
|
225 | - * @param AdminListTableFilters|null $filters to display list table filters |
|
226 | - */ |
|
227 | - public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null) |
|
228 | - { |
|
229 | - $this->_admin_page = $admin_page; |
|
230 | - $this->_req_data = $this->_admin_page->get_request_data(); |
|
231 | - $this->_view = $this->_admin_page->get_view(); |
|
232 | - $this->_views = empty($this->_views) ? $this->_admin_page->get_list_table_view_RLs() : $this->_views; |
|
233 | - $this->_current_page = $this->get_pagenum(); |
|
234 | - $this->_screen = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view(); |
|
235 | - $this->_yes_no = [ |
|
236 | - esc_html__('No', 'event_espresso'), |
|
237 | - esc_html__('Yes', 'event_espresso') |
|
238 | - ]; |
|
239 | - |
|
240 | - $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page'); |
|
241 | - |
|
242 | - $this->admin_list_table_filters = $filters instanceof AdminListTableFilters |
|
243 | - ? $filters |
|
244 | - : LoaderFactory::getShared(AdminListTableFilters::class); |
|
245 | - |
|
246 | - $this->_setup_data(); |
|
247 | - $this->_add_view_counts(); |
|
248 | - |
|
249 | - $this->_nonce_action_ref = $this->_view; |
|
250 | - |
|
251 | - $this->_set_properties(); |
|
252 | - |
|
253 | - // set primary column |
|
254 | - add_filter('list_table_primary_column', [$this, 'set_primary_column']); |
|
255 | - |
|
256 | - // set parent defaults |
|
257 | - parent::__construct($this->_wp_list_args); |
|
258 | - |
|
259 | - $this->prepare_items(); |
|
260 | - } |
|
261 | - |
|
262 | - |
|
263 | - /** |
|
264 | - * _setup_data |
|
265 | - * this method is used to setup the $_data, $_all_data_count, and _per_page properties |
|
266 | - * |
|
267 | - * @return void |
|
268 | - * @uses $this->_admin_page |
|
269 | - */ |
|
270 | - abstract protected function _setup_data(); |
|
271 | - |
|
272 | - |
|
273 | - /** |
|
274 | - * set the properties that this class needs to be able to execute wp_list_table properly |
|
275 | - * properties set: |
|
276 | - * _wp_list_args = what the arguments required for the parent _wp_list_table. |
|
277 | - * _columns = set the columns in an array. |
|
278 | - * _sortable_columns = columns that are sortable (array). |
|
279 | - * _hidden_columns = columns that are hidden (array) |
|
280 | - * _default_orderby = the default orderby for sorting. |
|
281 | - * |
|
282 | - * @abstract |
|
283 | - * @access protected |
|
284 | - * @return void |
|
285 | - */ |
|
286 | - abstract protected function _set_properties(); |
|
287 | - |
|
288 | - |
|
289 | - /** |
|
290 | - * _get_table_filters |
|
291 | - * We use this to assemble and return any filters that are associated with this table that help further refine what |
|
292 | - * gets shown in the table. |
|
293 | - * |
|
294 | - * @abstract |
|
295 | - * @access protected |
|
296 | - * @return string[] |
|
297 | - */ |
|
298 | - abstract protected function _get_table_filters(); |
|
299 | - |
|
300 | - |
|
301 | - /** |
|
302 | - * this is a method that child class will do to add counts to the views array so when views are displayed the |
|
303 | - * counts of the views is accurate. |
|
304 | - * |
|
305 | - * @abstract |
|
306 | - * @access protected |
|
307 | - * @return void |
|
308 | - */ |
|
309 | - abstract protected function _add_view_counts(); |
|
310 | - |
|
311 | - |
|
312 | - /** |
|
313 | - * _get_hidden_fields |
|
314 | - * returns a html string of hidden fields so if any table filters are used the current view will be respected. |
|
315 | - * |
|
316 | - * @return string |
|
317 | - */ |
|
318 | - protected function _get_hidden_fields() |
|
319 | - { |
|
320 | - $action = isset($this->_req_data['route']) ? $this->_req_data['route'] : ''; |
|
321 | - $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action; |
|
322 | - // if action is STILL empty, then we set it to default |
|
323 | - $action = empty($action) ? 'default' : $action; |
|
324 | - $field = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n"; |
|
325 | - $field .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n"; |
|
326 | - $field .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n"; |
|
327 | - |
|
328 | - $bulk_actions = $this->_get_bulk_actions(); |
|
329 | - foreach ($bulk_actions as $bulk_action => $label) { |
|
330 | - $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"' |
|
331 | - . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n"; |
|
332 | - } |
|
333 | - |
|
334 | - return $field; |
|
335 | - } |
|
336 | - |
|
337 | - |
|
338 | - /** |
|
339 | - * _set_column_info |
|
340 | - * we're using this to set the column headers property. |
|
341 | - * |
|
342 | - * @access protected |
|
343 | - * @return void |
|
344 | - */ |
|
345 | - protected function _set_column_info() |
|
346 | - { |
|
347 | - $columns = $this->get_columns(); |
|
348 | - $hidden = $this->get_hidden_columns(); |
|
349 | - $_sortable = $this->get_sortable_columns(); |
|
350 | - |
|
351 | - /** |
|
352 | - * Dynamic hook allowing for adding sortable columns in this list table. |
|
353 | - * Note that $this->screen->id is in the format |
|
354 | - * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
355 | - * table it is: event-espresso_page_espresso_messages. |
|
356 | - * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
357 | - * hook prefix ("event-espresso") will be different. |
|
358 | - * |
|
359 | - * @var array |
|
360 | - */ |
|
361 | - $_sortable = apply_filters( |
|
362 | - "FHEE_manage_{$this->screen->id}_sortable_columns", |
|
363 | - $_sortable, |
|
364 | - $this->_screen, |
|
365 | - $this |
|
366 | - ); |
|
367 | - |
|
368 | - $sortable = []; |
|
369 | - foreach ($_sortable as $id => $data) { |
|
370 | - if (empty($data)) { |
|
371 | - continue; |
|
372 | - } |
|
373 | - // fix for offset errors with WP_List_Table default get_columninfo() |
|
374 | - if (is_array($data)) { |
|
375 | - $_data[0] = key($data); |
|
376 | - $_data[1] = isset($data[1]) ? $data[1] : false; |
|
377 | - } else { |
|
378 | - $_data[0] = $data; |
|
379 | - } |
|
380 | - |
|
381 | - $data = (array) $data; |
|
382 | - |
|
383 | - if (! isset($data[1])) { |
|
384 | - $_data[1] = false; |
|
385 | - } |
|
386 | - |
|
387 | - $sortable[ $id ] = $_data; |
|
388 | - } |
|
389 | - $primary = $this->get_primary_column_name(); |
|
390 | - $this->_column_headers = [$columns, $hidden, $sortable, $primary]; |
|
391 | - } |
|
392 | - |
|
393 | - |
|
394 | - /** |
|
395 | - * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814) |
|
396 | - * |
|
397 | - * @return string |
|
398 | - */ |
|
399 | - protected function get_primary_column_name() |
|
400 | - { |
|
401 | - foreach (class_parents($this) as $parent) { |
|
402 | - if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) { |
|
403 | - return parent::get_primary_column_name(); |
|
404 | - } |
|
405 | - } |
|
406 | - return $this->_primary_column; |
|
407 | - } |
|
408 | - |
|
409 | - |
|
410 | - /** |
|
411 | - * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814) |
|
412 | - * |
|
413 | - * @param EE_Base_Class $item |
|
414 | - * @param string $column_name |
|
415 | - * @param string $primary |
|
416 | - * @return string |
|
417 | - */ |
|
418 | - protected function handle_row_actions($item, $column_name, $primary) |
|
419 | - { |
|
420 | - foreach (class_parents($this) as $parent) { |
|
421 | - if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) { |
|
422 | - return parent::handle_row_actions($item, $column_name, $primary); |
|
423 | - } |
|
424 | - } |
|
425 | - return ''; |
|
426 | - } |
|
427 | - |
|
428 | - |
|
429 | - /** |
|
430 | - * _get_bulk_actions |
|
431 | - * This is a wrapper called by WP_List_Table::get_bulk_actions() |
|
432 | - * |
|
433 | - * @access protected |
|
434 | - * @return array bulk_actions |
|
435 | - */ |
|
436 | - protected function _get_bulk_actions(): array |
|
437 | - { |
|
438 | - $actions = []; |
|
439 | - // the _views property should have the bulk_actions, so let's go through and extract them into a properly |
|
440 | - // formatted array for the wp_list_table(); |
|
441 | - foreach ($this->_views as $view => $args) { |
|
442 | - if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) { |
|
443 | - // each bulk action will correspond with a admin page route, so we can check whatever the capability is |
|
444 | - // for that page route and skip adding the bulk action if no access for the current logged in user. |
|
445 | - foreach ($args['bulk_action'] as $route => $label) { |
|
446 | - if ($this->_admin_page->check_user_access($route, true)) { |
|
447 | - $actions[ $route ] = $label; |
|
448 | - } |
|
449 | - } |
|
450 | - } |
|
451 | - } |
|
452 | - return $actions; |
|
453 | - } |
|
454 | - |
|
455 | - |
|
456 | - /** |
|
457 | - * Generate the table navigation above or below the table. |
|
458 | - * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions. |
|
459 | - * |
|
460 | - * @throws EE_Error |
|
461 | - * @since 4.9.44.rc.001 |
|
462 | - */ |
|
463 | - public function display_tablenav($which) |
|
464 | - { |
|
465 | - if ('top' === $which) { |
|
466 | - wp_nonce_field('bulk-' . $this->_args['plural']); |
|
467 | - } |
|
468 | - ?> |
|
26 | + const ACTION_COPY = 'duplicate'; |
|
27 | + |
|
28 | + const ACTION_DELETE = 'delete'; |
|
29 | + |
|
30 | + const ACTION_EDIT = 'edit'; |
|
31 | + |
|
32 | + const ACTION_RESTORE = 'restore'; |
|
33 | + |
|
34 | + const ACTION_TRASH = 'trash'; |
|
35 | + |
|
36 | + protected static $actions = [ |
|
37 | + self::ACTION_COPY, |
|
38 | + self::ACTION_DELETE, |
|
39 | + self::ACTION_EDIT, |
|
40 | + self::ACTION_RESTORE, |
|
41 | + self::ACTION_TRASH, |
|
42 | + ]; |
|
43 | + |
|
44 | + /** |
|
45 | + * holds the data that will be processed for the table |
|
46 | + * |
|
47 | + * @var array $_data |
|
48 | + */ |
|
49 | + protected $_data; |
|
50 | + |
|
51 | + |
|
52 | + /** |
|
53 | + * This holds the value of all the data available for the given view (for all pages). |
|
54 | + * |
|
55 | + * @var int $_all_data_count |
|
56 | + */ |
|
57 | + protected $_all_data_count; |
|
58 | + |
|
59 | + |
|
60 | + /** |
|
61 | + * Will contain the count of trashed items for the view label. |
|
62 | + * |
|
63 | + * @var int $_trashed_count |
|
64 | + */ |
|
65 | + protected $_trashed_count; |
|
66 | + |
|
67 | + |
|
68 | + /** |
|
69 | + * This is what will be referenced as the slug for the current screen |
|
70 | + * |
|
71 | + * @var string $_screen |
|
72 | + */ |
|
73 | + protected $_screen; |
|
74 | + |
|
75 | + |
|
76 | + /** |
|
77 | + * this is the EE_Admin_Page object |
|
78 | + * |
|
79 | + * @var EE_Admin_Page $_admin_page |
|
80 | + */ |
|
81 | + protected $_admin_page; |
|
82 | + |
|
83 | + |
|
84 | + /** |
|
85 | + * The current view |
|
86 | + * |
|
87 | + * @var string $_view |
|
88 | + */ |
|
89 | + protected $_view; |
|
90 | + |
|
91 | + |
|
92 | + /** |
|
93 | + * array of possible views for this table |
|
94 | + * |
|
95 | + * @var array $_views |
|
96 | + */ |
|
97 | + protected $_views; |
|
98 | + |
|
99 | + |
|
100 | + /** |
|
101 | + * An array of key => value pairs containing information about the current table |
|
102 | + * array( |
|
103 | + * 'plural' => 'plural label', |
|
104 | + * 'singular' => 'singular label', |
|
105 | + * 'ajax' => false, //whether to use ajax or not |
|
106 | + * 'screen' => null, //string used to reference what screen this is |
|
107 | + * (WP_List_table converts to screen object) |
|
108 | + * ) |
|
109 | + * |
|
110 | + * @var array $_wp_list_args |
|
111 | + */ |
|
112 | + protected $_wp_list_args; |
|
113 | + |
|
114 | + /** |
|
115 | + * an array of column names |
|
116 | + * array( |
|
117 | + * 'internal-name' => 'Title' |
|
118 | + * ) |
|
119 | + * |
|
120 | + * @var array $_columns |
|
121 | + */ |
|
122 | + protected $_columns; |
|
123 | + |
|
124 | + /** |
|
125 | + * An array of sortable columns |
|
126 | + * array( |
|
127 | + * 'internal-name' => 'orderby' //or |
|
128 | + * 'internal-name' => array( 'orderby', true ) |
|
129 | + * ) |
|
130 | + * |
|
131 | + * @var array $_sortable_columns |
|
132 | + */ |
|
133 | + protected $_sortable_columns; |
|
134 | + |
|
135 | + /** |
|
136 | + * callback method used to perform AJAX row reordering |
|
137 | + * |
|
138 | + * @var string $_ajax_sorting_callback |
|
139 | + */ |
|
140 | + protected $_ajax_sorting_callback; |
|
141 | + |
|
142 | + /** |
|
143 | + * An array of hidden columns (if needed) |
|
144 | + * array('internal-name', 'internal-name') |
|
145 | + * |
|
146 | + * @var array $_hidden_columns |
|
147 | + */ |
|
148 | + protected $_hidden_columns; |
|
149 | + |
|
150 | + /** |
|
151 | + * holds the per_page value |
|
152 | + * |
|
153 | + * @var int $_per_page |
|
154 | + */ |
|
155 | + protected $_per_page; |
|
156 | + |
|
157 | + /** |
|
158 | + * holds what page number is currently being viewed |
|
159 | + * |
|
160 | + * @var int $_current_page |
|
161 | + */ |
|
162 | + protected $_current_page; |
|
163 | + |
|
164 | + /** |
|
165 | + * the reference string for the nonce_action |
|
166 | + * |
|
167 | + * @var string $_nonce_action_ref |
|
168 | + */ |
|
169 | + protected $_nonce_action_ref; |
|
170 | + |
|
171 | + /** |
|
172 | + * property to hold incoming request data (as set by the admin_page_core) |
|
173 | + * |
|
174 | + * @var array $_req_data |
|
175 | + */ |
|
176 | + protected $_req_data; |
|
177 | + |
|
178 | + |
|
179 | + /** |
|
180 | + * yes / no array for admin form fields |
|
181 | + * |
|
182 | + * @var array $_yes_no |
|
183 | + */ |
|
184 | + protected $_yes_no = []; |
|
185 | + |
|
186 | + /** |
|
187 | + * Array describing buttons that should appear at the bottom of the page |
|
188 | + * Keys are strings that represent the button's function (specifically a key in _labels['buttons']), |
|
189 | + * and the values are another array with the following keys |
|
190 | + * array( |
|
191 | + * 'route' => 'page_route', |
|
192 | + * 'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button. |
|
193 | + * ) |
|
194 | + * |
|
195 | + * @var array $_bottom_buttons |
|
196 | + */ |
|
197 | + protected $_bottom_buttons = []; |
|
198 | + |
|
199 | + |
|
200 | + /** |
|
201 | + * Used to indicate what should be the primary column for the list table. |
|
202 | + * If not present then falls back to what WP calculates |
|
203 | + * as the primary column. |
|
204 | + * |
|
205 | + * @type string $_primary_column |
|
206 | + */ |
|
207 | + protected $_primary_column = ''; |
|
208 | + |
|
209 | + |
|
210 | + /** |
|
211 | + * Used to indicate whether the table has a checkbox column or not. |
|
212 | + * |
|
213 | + * @type bool $_has_checkbox_column |
|
214 | + */ |
|
215 | + protected $_has_checkbox_column = false; |
|
216 | + |
|
217 | + /** |
|
218 | + * @var AdminListTableFilters|null |
|
219 | + */ |
|
220 | + protected ?AdminListTableFilters $admin_list_table_filters = null; |
|
221 | + |
|
222 | + |
|
223 | + /** |
|
224 | + * @param EE_Admin_Page $admin_page we use this for obtaining everything we need in the list table |
|
225 | + * @param AdminListTableFilters|null $filters to display list table filters |
|
226 | + */ |
|
227 | + public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null) |
|
228 | + { |
|
229 | + $this->_admin_page = $admin_page; |
|
230 | + $this->_req_data = $this->_admin_page->get_request_data(); |
|
231 | + $this->_view = $this->_admin_page->get_view(); |
|
232 | + $this->_views = empty($this->_views) ? $this->_admin_page->get_list_table_view_RLs() : $this->_views; |
|
233 | + $this->_current_page = $this->get_pagenum(); |
|
234 | + $this->_screen = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view(); |
|
235 | + $this->_yes_no = [ |
|
236 | + esc_html__('No', 'event_espresso'), |
|
237 | + esc_html__('Yes', 'event_espresso') |
|
238 | + ]; |
|
239 | + |
|
240 | + $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page'); |
|
241 | + |
|
242 | + $this->admin_list_table_filters = $filters instanceof AdminListTableFilters |
|
243 | + ? $filters |
|
244 | + : LoaderFactory::getShared(AdminListTableFilters::class); |
|
245 | + |
|
246 | + $this->_setup_data(); |
|
247 | + $this->_add_view_counts(); |
|
248 | + |
|
249 | + $this->_nonce_action_ref = $this->_view; |
|
250 | + |
|
251 | + $this->_set_properties(); |
|
252 | + |
|
253 | + // set primary column |
|
254 | + add_filter('list_table_primary_column', [$this, 'set_primary_column']); |
|
255 | + |
|
256 | + // set parent defaults |
|
257 | + parent::__construct($this->_wp_list_args); |
|
258 | + |
|
259 | + $this->prepare_items(); |
|
260 | + } |
|
261 | + |
|
262 | + |
|
263 | + /** |
|
264 | + * _setup_data |
|
265 | + * this method is used to setup the $_data, $_all_data_count, and _per_page properties |
|
266 | + * |
|
267 | + * @return void |
|
268 | + * @uses $this->_admin_page |
|
269 | + */ |
|
270 | + abstract protected function _setup_data(); |
|
271 | + |
|
272 | + |
|
273 | + /** |
|
274 | + * set the properties that this class needs to be able to execute wp_list_table properly |
|
275 | + * properties set: |
|
276 | + * _wp_list_args = what the arguments required for the parent _wp_list_table. |
|
277 | + * _columns = set the columns in an array. |
|
278 | + * _sortable_columns = columns that are sortable (array). |
|
279 | + * _hidden_columns = columns that are hidden (array) |
|
280 | + * _default_orderby = the default orderby for sorting. |
|
281 | + * |
|
282 | + * @abstract |
|
283 | + * @access protected |
|
284 | + * @return void |
|
285 | + */ |
|
286 | + abstract protected function _set_properties(); |
|
287 | + |
|
288 | + |
|
289 | + /** |
|
290 | + * _get_table_filters |
|
291 | + * We use this to assemble and return any filters that are associated with this table that help further refine what |
|
292 | + * gets shown in the table. |
|
293 | + * |
|
294 | + * @abstract |
|
295 | + * @access protected |
|
296 | + * @return string[] |
|
297 | + */ |
|
298 | + abstract protected function _get_table_filters(); |
|
299 | + |
|
300 | + |
|
301 | + /** |
|
302 | + * this is a method that child class will do to add counts to the views array so when views are displayed the |
|
303 | + * counts of the views is accurate. |
|
304 | + * |
|
305 | + * @abstract |
|
306 | + * @access protected |
|
307 | + * @return void |
|
308 | + */ |
|
309 | + abstract protected function _add_view_counts(); |
|
310 | + |
|
311 | + |
|
312 | + /** |
|
313 | + * _get_hidden_fields |
|
314 | + * returns a html string of hidden fields so if any table filters are used the current view will be respected. |
|
315 | + * |
|
316 | + * @return string |
|
317 | + */ |
|
318 | + protected function _get_hidden_fields() |
|
319 | + { |
|
320 | + $action = isset($this->_req_data['route']) ? $this->_req_data['route'] : ''; |
|
321 | + $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action; |
|
322 | + // if action is STILL empty, then we set it to default |
|
323 | + $action = empty($action) ? 'default' : $action; |
|
324 | + $field = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n"; |
|
325 | + $field .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n"; |
|
326 | + $field .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n"; |
|
327 | + |
|
328 | + $bulk_actions = $this->_get_bulk_actions(); |
|
329 | + foreach ($bulk_actions as $bulk_action => $label) { |
|
330 | + $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"' |
|
331 | + . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n"; |
|
332 | + } |
|
333 | + |
|
334 | + return $field; |
|
335 | + } |
|
336 | + |
|
337 | + |
|
338 | + /** |
|
339 | + * _set_column_info |
|
340 | + * we're using this to set the column headers property. |
|
341 | + * |
|
342 | + * @access protected |
|
343 | + * @return void |
|
344 | + */ |
|
345 | + protected function _set_column_info() |
|
346 | + { |
|
347 | + $columns = $this->get_columns(); |
|
348 | + $hidden = $this->get_hidden_columns(); |
|
349 | + $_sortable = $this->get_sortable_columns(); |
|
350 | + |
|
351 | + /** |
|
352 | + * Dynamic hook allowing for adding sortable columns in this list table. |
|
353 | + * Note that $this->screen->id is in the format |
|
354 | + * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
355 | + * table it is: event-espresso_page_espresso_messages. |
|
356 | + * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
357 | + * hook prefix ("event-espresso") will be different. |
|
358 | + * |
|
359 | + * @var array |
|
360 | + */ |
|
361 | + $_sortable = apply_filters( |
|
362 | + "FHEE_manage_{$this->screen->id}_sortable_columns", |
|
363 | + $_sortable, |
|
364 | + $this->_screen, |
|
365 | + $this |
|
366 | + ); |
|
367 | + |
|
368 | + $sortable = []; |
|
369 | + foreach ($_sortable as $id => $data) { |
|
370 | + if (empty($data)) { |
|
371 | + continue; |
|
372 | + } |
|
373 | + // fix for offset errors with WP_List_Table default get_columninfo() |
|
374 | + if (is_array($data)) { |
|
375 | + $_data[0] = key($data); |
|
376 | + $_data[1] = isset($data[1]) ? $data[1] : false; |
|
377 | + } else { |
|
378 | + $_data[0] = $data; |
|
379 | + } |
|
380 | + |
|
381 | + $data = (array) $data; |
|
382 | + |
|
383 | + if (! isset($data[1])) { |
|
384 | + $_data[1] = false; |
|
385 | + } |
|
386 | + |
|
387 | + $sortable[ $id ] = $_data; |
|
388 | + } |
|
389 | + $primary = $this->get_primary_column_name(); |
|
390 | + $this->_column_headers = [$columns, $hidden, $sortable, $primary]; |
|
391 | + } |
|
392 | + |
|
393 | + |
|
394 | + /** |
|
395 | + * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814) |
|
396 | + * |
|
397 | + * @return string |
|
398 | + */ |
|
399 | + protected function get_primary_column_name() |
|
400 | + { |
|
401 | + foreach (class_parents($this) as $parent) { |
|
402 | + if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) { |
|
403 | + return parent::get_primary_column_name(); |
|
404 | + } |
|
405 | + } |
|
406 | + return $this->_primary_column; |
|
407 | + } |
|
408 | + |
|
409 | + |
|
410 | + /** |
|
411 | + * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814) |
|
412 | + * |
|
413 | + * @param EE_Base_Class $item |
|
414 | + * @param string $column_name |
|
415 | + * @param string $primary |
|
416 | + * @return string |
|
417 | + */ |
|
418 | + protected function handle_row_actions($item, $column_name, $primary) |
|
419 | + { |
|
420 | + foreach (class_parents($this) as $parent) { |
|
421 | + if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) { |
|
422 | + return parent::handle_row_actions($item, $column_name, $primary); |
|
423 | + } |
|
424 | + } |
|
425 | + return ''; |
|
426 | + } |
|
427 | + |
|
428 | + |
|
429 | + /** |
|
430 | + * _get_bulk_actions |
|
431 | + * This is a wrapper called by WP_List_Table::get_bulk_actions() |
|
432 | + * |
|
433 | + * @access protected |
|
434 | + * @return array bulk_actions |
|
435 | + */ |
|
436 | + protected function _get_bulk_actions(): array |
|
437 | + { |
|
438 | + $actions = []; |
|
439 | + // the _views property should have the bulk_actions, so let's go through and extract them into a properly |
|
440 | + // formatted array for the wp_list_table(); |
|
441 | + foreach ($this->_views as $view => $args) { |
|
442 | + if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) { |
|
443 | + // each bulk action will correspond with a admin page route, so we can check whatever the capability is |
|
444 | + // for that page route and skip adding the bulk action if no access for the current logged in user. |
|
445 | + foreach ($args['bulk_action'] as $route => $label) { |
|
446 | + if ($this->_admin_page->check_user_access($route, true)) { |
|
447 | + $actions[ $route ] = $label; |
|
448 | + } |
|
449 | + } |
|
450 | + } |
|
451 | + } |
|
452 | + return $actions; |
|
453 | + } |
|
454 | + |
|
455 | + |
|
456 | + /** |
|
457 | + * Generate the table navigation above or below the table. |
|
458 | + * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions. |
|
459 | + * |
|
460 | + * @throws EE_Error |
|
461 | + * @since 4.9.44.rc.001 |
|
462 | + */ |
|
463 | + public function display_tablenav($which) |
|
464 | + { |
|
465 | + if ('top' === $which) { |
|
466 | + wp_nonce_field('bulk-' . $this->_args['plural']); |
|
467 | + } |
|
468 | + ?> |
|
469 | 469 | <div class="tablenav <?php echo esc_attr($which); ?>"> |
470 | 470 | <?php if ($this->_get_bulk_actions()) { ?> |
471 | 471 | <div class="alignleft actions bulkactions"> |
472 | 472 | <?php $this->bulk_actions(); ?> |
473 | 473 | </div> |
474 | 474 | <?php } |
475 | - $this->extra_tablenav($which); |
|
476 | - $this->pagination($which); |
|
477 | - ?> |
|
475 | + $this->extra_tablenav($which); |
|
476 | + $this->pagination($which); |
|
477 | + ?> |
|
478 | 478 | |
479 | 479 | <br class="clear" /> |
480 | 480 | </div> |
481 | 481 | <?php |
482 | - } |
|
483 | - |
|
484 | - |
|
485 | - /** |
|
486 | - * _filters |
|
487 | - * This receives the filters array from children _get_table_filters() and assembles the string including the filter |
|
488 | - * button. |
|
489 | - * |
|
490 | - * @access private |
|
491 | - * @return void echos html showing filters |
|
492 | - */ |
|
493 | - private function _filters(): void |
|
494 | - { |
|
495 | - $classname = get_class($this); |
|
496 | - $filters = apply_filters( |
|
497 | - "FHEE__{$classname}__filters", |
|
498 | - $this->_get_table_filters(), |
|
499 | - $this, |
|
500 | - $this->_screen |
|
501 | - ); |
|
502 | - |
|
503 | - if (empty($filters)) { |
|
504 | - return; |
|
505 | - } |
|
506 | - |
|
507 | - $this->admin_list_table_filters->filters( |
|
508 | - $filters, |
|
509 | - $this->get_admin_page()->get_current_page_view_url() |
|
510 | - ); |
|
511 | - } |
|
512 | - |
|
513 | - |
|
514 | - /** |
|
515 | - * Callback for 'list_table_primary_column' WordPress filter |
|
516 | - * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary |
|
517 | - * column when class is instantiated. |
|
518 | - * |
|
519 | - * @param string $column_name |
|
520 | - * @return string |
|
521 | - * @see WP_List_Table::get_primary_column_name |
|
522 | - */ |
|
523 | - public function set_primary_column($column_name) |
|
524 | - { |
|
525 | - return ! empty($this->_primary_column) ? $this->_primary_column : $column_name; |
|
526 | - } |
|
527 | - |
|
528 | - |
|
529 | - /** |
|
530 | - * |
|
531 | - */ |
|
532 | - public function prepare_items() |
|
533 | - { |
|
534 | - $this->_set_column_info(); |
|
535 | - $this->process_bulk_action(); |
|
536 | - |
|
537 | - $this->items = $this->_data; |
|
538 | - $this->set_pagination_args( |
|
539 | - [ |
|
540 | - 'total_items' => $this->_all_data_count, |
|
541 | - 'per_page' => $this->_per_page, |
|
542 | - 'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page), |
|
543 | - ] |
|
544 | - ); |
|
545 | - } |
|
546 | - |
|
547 | - |
|
548 | - /** |
|
549 | - * @param object|array $item |
|
550 | - * @return string html content for the column |
|
551 | - */ |
|
552 | - protected function column_cb($item) |
|
553 | - { |
|
554 | - return ''; |
|
555 | - } |
|
556 | - |
|
557 | - |
|
558 | - /** |
|
559 | - * This column is the default for when there is no defined column method for a registered column. |
|
560 | - * This can be overridden by child classes, but allows for hooking in for custom columns. |
|
561 | - * |
|
562 | - * @param EE_Base_Class $item |
|
563 | - * @param string $column_name The column being called. |
|
564 | - * @return string html content for the column |
|
565 | - */ |
|
566 | - public function column_default($item, $column_name) |
|
567 | - { |
|
568 | - /** |
|
569 | - * Dynamic hook allowing for adding additional column content in this list table. |
|
570 | - * Note that $this->screen->id is in the format |
|
571 | - * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
572 | - * table it is: event-espresso_page_espresso_messages. |
|
573 | - * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
574 | - * hook prefix ("event-espresso") will be different. |
|
575 | - */ |
|
576 | - ob_start(); |
|
577 | - do_action( |
|
578 | - 'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id, |
|
579 | - $item, |
|
580 | - $this->_screen |
|
581 | - ); |
|
582 | - $content = ob_get_clean(); |
|
583 | - return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content; |
|
584 | - } |
|
585 | - |
|
586 | - |
|
587 | - /** |
|
588 | - * Get a list of columns. The format is: |
|
589 | - * 'internal-name' => 'Title' |
|
590 | - * |
|
591 | - * @return array |
|
592 | - * @since 3.1.0 |
|
593 | - * @access public |
|
594 | - * @abstract |
|
595 | - */ |
|
596 | - public function get_columns() |
|
597 | - { |
|
598 | - /** |
|
599 | - * Dynamic hook allowing for adding additional columns in this list table. |
|
600 | - * Note that $this->screen->id is in the format |
|
601 | - * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
602 | - * table it is: event-espresso_page_espresso_messages. |
|
603 | - * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
604 | - * hook prefix ("event-espresso") will be different. |
|
605 | - * |
|
606 | - * @var array |
|
607 | - */ |
|
608 | - return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this); |
|
609 | - } |
|
610 | - |
|
611 | - |
|
612 | - /** |
|
613 | - * Get an associative array ( id => link ) with the list |
|
614 | - * of views available on this table. |
|
615 | - * |
|
616 | - * @return array |
|
617 | - * @since 3.1.0 |
|
618 | - * @access protected |
|
619 | - */ |
|
620 | - public function get_views() |
|
621 | - { |
|
622 | - return $this->_views; |
|
623 | - } |
|
624 | - |
|
625 | - |
|
626 | - /** |
|
627 | - * Generate the views html. |
|
628 | - */ |
|
629 | - public function display_views() |
|
630 | - { |
|
631 | - $views = $this->get_views(); |
|
632 | - $assembled_views = []; |
|
633 | - |
|
634 | - if (empty($views)) { |
|
635 | - return; |
|
636 | - } |
|
637 | - echo "<ul class='subsubsub'>\n"; |
|
638 | - foreach ($views as $view) { |
|
639 | - $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0; |
|
640 | - if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) { |
|
641 | - $filter = "<li"; |
|
642 | - $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : ''; |
|
643 | - $filter .= ">"; |
|
644 | - $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>'; |
|
645 | - $filter .= '<span class="count">(' . $count . ')</span>'; |
|
646 | - $filter .= '</li>'; |
|
647 | - $assembled_views[ $view['slug'] ] = $filter; |
|
648 | - } |
|
649 | - } |
|
650 | - |
|
651 | - echo ! empty($assembled_views) |
|
652 | - ? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views) |
|
653 | - : ''; |
|
654 | - echo "</ul>"; |
|
655 | - } |
|
656 | - |
|
657 | - |
|
658 | - /** |
|
659 | - * Generates content for a single row of the table |
|
660 | - * |
|
661 | - * @param EE_Base_Class $item The current item |
|
662 | - * @since 4.1 |
|
663 | - * @access public |
|
664 | - */ |
|
665 | - public function single_row($item) |
|
666 | - { |
|
667 | - $row_class = $this->_get_row_class($item); |
|
668 | - echo '<tr class="' . esc_attr($row_class) . '">'; |
|
669 | - $this->single_row_columns($item); // already escaped |
|
670 | - echo '</tr>'; |
|
671 | - } |
|
672 | - |
|
673 | - |
|
674 | - /** |
|
675 | - * This simply sets up the row class for the table rows. |
|
676 | - * Allows for easier overriding of child methods for setting up sorting. |
|
677 | - * |
|
678 | - * @param EE_Base_Class $item the current item |
|
679 | - * @return string |
|
680 | - */ |
|
681 | - protected function _get_row_class($item) |
|
682 | - { |
|
683 | - static $row_class = ''; |
|
684 | - $row_class = ($row_class === '' ? 'alternate' : ''); |
|
685 | - |
|
686 | - $new_row_class = $row_class; |
|
687 | - |
|
688 | - if (! empty($this->_ajax_sorting_callback)) { |
|
689 | - $new_row_class .= ' rowsortable'; |
|
690 | - } |
|
691 | - |
|
692 | - return $new_row_class; |
|
693 | - } |
|
694 | - |
|
695 | - |
|
696 | - /** |
|
697 | - * @return array |
|
698 | - */ |
|
699 | - public function get_sortable_columns() |
|
700 | - { |
|
701 | - return (array) $this->_sortable_columns; |
|
702 | - } |
|
703 | - |
|
704 | - |
|
705 | - /** |
|
706 | - * @return string |
|
707 | - */ |
|
708 | - public function get_ajax_sorting_callback() |
|
709 | - { |
|
710 | - return $this->_ajax_sorting_callback; |
|
711 | - } |
|
712 | - |
|
713 | - |
|
714 | - /** |
|
715 | - * @return array |
|
716 | - */ |
|
717 | - public function get_hidden_columns() |
|
718 | - { |
|
719 | - $user_id = get_current_user_id(); |
|
720 | - $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id); |
|
721 | - if (empty($has_default) && ! empty($this->_hidden_columns)) { |
|
722 | - update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true); |
|
723 | - update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true); |
|
724 | - } |
|
725 | - $ref = 'manage' . $this->screen->id . 'columnshidden'; |
|
726 | - return (array) get_user_option($ref, $user_id); |
|
727 | - } |
|
728 | - |
|
729 | - |
|
730 | - /** |
|
731 | - * Generates the columns for a single row of the table. |
|
732 | - * Overridden from wp_list_table so as to allow us to filter the column content for a given |
|
733 | - * column. |
|
734 | - * |
|
735 | - * @param EE_Base_Class $item The current item |
|
736 | - * @since 3.1.0 |
|
737 | - */ |
|
738 | - public function single_row_columns($item) |
|
739 | - { |
|
740 | - [$columns, $hidden, $sortable, $primary] = $this->get_column_info(); |
|
741 | - |
|
742 | - foreach ($columns as $column_name => $column_display_name) { |
|
743 | - |
|
744 | - /** |
|
745 | - * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns |
|
746 | - * are hidden or not instead of using "display:none;". This bit of code provides backward compat. |
|
747 | - */ |
|
748 | - $hidden_class = in_array($column_name, $hidden) ? ' hidden' : ''; |
|
749 | - |
|
750 | - $classes = $column_name . ' column-' . $column_name . $hidden_class; |
|
751 | - if ($primary === $column_name) { |
|
752 | - $classes .= ' has-row-actions column-primary'; |
|
753 | - } |
|
754 | - |
|
755 | - $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"'; |
|
756 | - |
|
757 | - $class = 'class="' . esc_attr($classes) . '"'; |
|
758 | - |
|
759 | - $attributes = "{$class}{$data}"; |
|
760 | - |
|
761 | - if ($column_name === 'cb') { |
|
762 | - echo '<th scope="row" class="check-column">'; |
|
763 | - echo apply_filters( |
|
764 | - 'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content', |
|
765 | - $this->column_cb($item), // already escaped |
|
766 | - $item, |
|
767 | - $this |
|
768 | - ); |
|
769 | - echo '</th>'; |
|
770 | - } elseif (method_exists($this, "column_$column_name")) { |
|
771 | - echo "<td $attributes>"; // already escaped |
|
772 | - echo apply_filters( |
|
773 | - 'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content', |
|
774 | - call_user_func([$this, "column_$column_name"], $item), |
|
775 | - $item, |
|
776 | - $this |
|
777 | - ); |
|
778 | - echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags()); |
|
779 | - echo "</td>"; |
|
780 | - } else { |
|
781 | - echo "<td $attributes>"; // already escaped |
|
782 | - echo apply_filters( |
|
783 | - 'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content', |
|
784 | - $this->column_default($item, $column_name), |
|
785 | - $item, |
|
786 | - $column_name, |
|
787 | - $this |
|
788 | - ); |
|
789 | - echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags()); |
|
790 | - echo "</td>"; |
|
791 | - } |
|
792 | - } |
|
793 | - } |
|
794 | - |
|
795 | - |
|
796 | - /** |
|
797 | - * Extra controls to be displayed between bulk actions and pagination |
|
798 | - * |
|
799 | - * @access public |
|
800 | - * @param string $which |
|
801 | - * @throws EE_Error |
|
802 | - */ |
|
803 | - public function extra_tablenav($which) |
|
804 | - { |
|
805 | - if ($which === 'top') { |
|
806 | - $this->_filters(); |
|
807 | - echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags()); |
|
808 | - } else { |
|
809 | - echo '<div class="list-table-bottom-buttons alignleft actions">'; |
|
810 | - foreach ($this->_bottom_buttons as $type => $action) { |
|
811 | - $route = $action['route'] ?? ''; |
|
812 | - $extra_request = $action['extra_request'] ?? ''; |
|
813 | - $btn_class = $action['btn_class'] ?? 'button button--secondary'; |
|
814 | - // already escaped |
|
815 | - echo wp_kses($this->_admin_page->get_action_link_or_button( |
|
816 | - $route, |
|
817 | - $type, |
|
818 | - $extra_request, |
|
819 | - $btn_class |
|
820 | - ), AllowedTags::getWithFormTags()); |
|
821 | - } |
|
822 | - do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen); |
|
823 | - echo '</div>'; |
|
824 | - } |
|
825 | - } |
|
826 | - |
|
827 | - |
|
828 | - /** |
|
829 | - * Get an associative array ( option_name => option_title ) with the list |
|
830 | - * of bulk actions available on this table. |
|
831 | - * |
|
832 | - * @return array |
|
833 | - * @since 3.1.0 |
|
834 | - * @access protected |
|
835 | - */ |
|
836 | - public function get_bulk_actions() |
|
837 | - { |
|
838 | - return (array) $this->_get_bulk_actions(); |
|
839 | - } |
|
840 | - |
|
841 | - |
|
842 | - /** |
|
843 | - * Processing bulk actions. |
|
844 | - */ |
|
845 | - public function process_bulk_action() |
|
846 | - { |
|
847 | - // this is not used it is handled by the child EE_Admin_Page class (routes). However, including here for |
|
848 | - // reference in case there is a case where it gets used. |
|
849 | - } |
|
850 | - |
|
851 | - |
|
852 | - /** |
|
853 | - * returns the EE admin page this list table is associated with |
|
854 | - * |
|
855 | - * @return EE_Admin_Page |
|
856 | - */ |
|
857 | - public function get_admin_page() |
|
858 | - { |
|
859 | - return $this->_admin_page; |
|
860 | - } |
|
861 | - |
|
862 | - |
|
863 | - /** |
|
864 | - * A "helper" function for all children to provide an html string of |
|
865 | - * actions to output in their content. It is preferable for child classes |
|
866 | - * to use this method for generating their actions content so that it's |
|
867 | - * filterable by plugins |
|
868 | - * |
|
869 | - * @param string $action_container what are the html container |
|
870 | - * elements for this actions string? |
|
871 | - * @param string $action_class What class is for the container |
|
872 | - * element. |
|
873 | - * @param string $action_items The contents for the action items |
|
874 | - * container. This is filtered before |
|
875 | - * returned. |
|
876 | - * @param string $action_id What id (optional) is used for the |
|
877 | - * container element. |
|
878 | - * @param EE_Base_Class $item The object for the column displaying |
|
879 | - * the actions. |
|
880 | - * @return string The assembled action elements container. |
|
881 | - */ |
|
882 | - protected function _action_string( |
|
883 | - $action_items, |
|
884 | - $item, |
|
885 | - $action_container = 'ul', |
|
886 | - $action_class = '', |
|
887 | - $action_id = '' |
|
888 | - ) { |
|
889 | - $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : ''; |
|
890 | - $action_id = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : ''; |
|
891 | - $open_tag = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : ''; |
|
892 | - $close_tag = ! empty($action_container) ? '</' . $action_container . '>' : ''; |
|
893 | - try { |
|
894 | - $content = apply_filters( |
|
895 | - 'FHEE__EE_Admin_List_Table___action_string__action_items', |
|
896 | - $action_items, |
|
897 | - $item, |
|
898 | - $this |
|
899 | - ); |
|
900 | - } catch (Exception $e) { |
|
901 | - if (WP_DEBUG) { |
|
902 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
903 | - } |
|
904 | - $content = $action_items; |
|
905 | - } |
|
906 | - return "{$open_tag}{$content}{$close_tag}"; |
|
907 | - } |
|
908 | - |
|
909 | - |
|
910 | - /** |
|
911 | - * @return string |
|
912 | - */ |
|
913 | - protected function getReturnUrl() |
|
914 | - { |
|
915 | - $host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST'); |
|
916 | - $uri = $this->_admin_page->get_request()->getServerParam('REQUEST_URI'); |
|
917 | - return urlencode(esc_url_raw("//{$host}{$uri}")); |
|
918 | - } |
|
919 | - |
|
920 | - |
|
921 | - /** |
|
922 | - * @param string $id |
|
923 | - * @param string $content |
|
924 | - * @param string $align start (default), center, end |
|
925 | - * @return string |
|
926 | - * @since 5.0.0.p |
|
927 | - */ |
|
928 | - protected function columnContent($id, $content, $align = 'start') |
|
929 | - { |
|
930 | - if (! isset($this->_columns[ $id ])) { |
|
931 | - throw new DomainException('missing column id'); |
|
932 | - } |
|
933 | - $heading = $id !== 'cb' ? $this->_columns[ $id ] : ''; |
|
934 | - $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start'; |
|
935 | - $align = "ee-responsive-table-cell--{$align}"; |
|
936 | - |
|
937 | - $html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>"; |
|
938 | - $html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>"; |
|
939 | - $html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>"; |
|
940 | - $html .= "</div>"; |
|
941 | - return $html; |
|
942 | - } |
|
943 | - |
|
944 | - |
|
945 | - protected function actionsModalMenu($actions): string |
|
946 | - { |
|
947 | - return ' |
|
482 | + } |
|
483 | + |
|
484 | + |
|
485 | + /** |
|
486 | + * _filters |
|
487 | + * This receives the filters array from children _get_table_filters() and assembles the string including the filter |
|
488 | + * button. |
|
489 | + * |
|
490 | + * @access private |
|
491 | + * @return void echos html showing filters |
|
492 | + */ |
|
493 | + private function _filters(): void |
|
494 | + { |
|
495 | + $classname = get_class($this); |
|
496 | + $filters = apply_filters( |
|
497 | + "FHEE__{$classname}__filters", |
|
498 | + $this->_get_table_filters(), |
|
499 | + $this, |
|
500 | + $this->_screen |
|
501 | + ); |
|
502 | + |
|
503 | + if (empty($filters)) { |
|
504 | + return; |
|
505 | + } |
|
506 | + |
|
507 | + $this->admin_list_table_filters->filters( |
|
508 | + $filters, |
|
509 | + $this->get_admin_page()->get_current_page_view_url() |
|
510 | + ); |
|
511 | + } |
|
512 | + |
|
513 | + |
|
514 | + /** |
|
515 | + * Callback for 'list_table_primary_column' WordPress filter |
|
516 | + * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary |
|
517 | + * column when class is instantiated. |
|
518 | + * |
|
519 | + * @param string $column_name |
|
520 | + * @return string |
|
521 | + * @see WP_List_Table::get_primary_column_name |
|
522 | + */ |
|
523 | + public function set_primary_column($column_name) |
|
524 | + { |
|
525 | + return ! empty($this->_primary_column) ? $this->_primary_column : $column_name; |
|
526 | + } |
|
527 | + |
|
528 | + |
|
529 | + /** |
|
530 | + * |
|
531 | + */ |
|
532 | + public function prepare_items() |
|
533 | + { |
|
534 | + $this->_set_column_info(); |
|
535 | + $this->process_bulk_action(); |
|
536 | + |
|
537 | + $this->items = $this->_data; |
|
538 | + $this->set_pagination_args( |
|
539 | + [ |
|
540 | + 'total_items' => $this->_all_data_count, |
|
541 | + 'per_page' => $this->_per_page, |
|
542 | + 'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page), |
|
543 | + ] |
|
544 | + ); |
|
545 | + } |
|
546 | + |
|
547 | + |
|
548 | + /** |
|
549 | + * @param object|array $item |
|
550 | + * @return string html content for the column |
|
551 | + */ |
|
552 | + protected function column_cb($item) |
|
553 | + { |
|
554 | + return ''; |
|
555 | + } |
|
556 | + |
|
557 | + |
|
558 | + /** |
|
559 | + * This column is the default for when there is no defined column method for a registered column. |
|
560 | + * This can be overridden by child classes, but allows for hooking in for custom columns. |
|
561 | + * |
|
562 | + * @param EE_Base_Class $item |
|
563 | + * @param string $column_name The column being called. |
|
564 | + * @return string html content for the column |
|
565 | + */ |
|
566 | + public function column_default($item, $column_name) |
|
567 | + { |
|
568 | + /** |
|
569 | + * Dynamic hook allowing for adding additional column content in this list table. |
|
570 | + * Note that $this->screen->id is in the format |
|
571 | + * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
572 | + * table it is: event-espresso_page_espresso_messages. |
|
573 | + * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
574 | + * hook prefix ("event-espresso") will be different. |
|
575 | + */ |
|
576 | + ob_start(); |
|
577 | + do_action( |
|
578 | + 'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id, |
|
579 | + $item, |
|
580 | + $this->_screen |
|
581 | + ); |
|
582 | + $content = ob_get_clean(); |
|
583 | + return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content; |
|
584 | + } |
|
585 | + |
|
586 | + |
|
587 | + /** |
|
588 | + * Get a list of columns. The format is: |
|
589 | + * 'internal-name' => 'Title' |
|
590 | + * |
|
591 | + * @return array |
|
592 | + * @since 3.1.0 |
|
593 | + * @access public |
|
594 | + * @abstract |
|
595 | + */ |
|
596 | + public function get_columns() |
|
597 | + { |
|
598 | + /** |
|
599 | + * Dynamic hook allowing for adding additional columns in this list table. |
|
600 | + * Note that $this->screen->id is in the format |
|
601 | + * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}. So for the messages list |
|
602 | + * table it is: event-espresso_page_espresso_messages. |
|
603 | + * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the |
|
604 | + * hook prefix ("event-espresso") will be different. |
|
605 | + * |
|
606 | + * @var array |
|
607 | + */ |
|
608 | + return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this); |
|
609 | + } |
|
610 | + |
|
611 | + |
|
612 | + /** |
|
613 | + * Get an associative array ( id => link ) with the list |
|
614 | + * of views available on this table. |
|
615 | + * |
|
616 | + * @return array |
|
617 | + * @since 3.1.0 |
|
618 | + * @access protected |
|
619 | + */ |
|
620 | + public function get_views() |
|
621 | + { |
|
622 | + return $this->_views; |
|
623 | + } |
|
624 | + |
|
625 | + |
|
626 | + /** |
|
627 | + * Generate the views html. |
|
628 | + */ |
|
629 | + public function display_views() |
|
630 | + { |
|
631 | + $views = $this->get_views(); |
|
632 | + $assembled_views = []; |
|
633 | + |
|
634 | + if (empty($views)) { |
|
635 | + return; |
|
636 | + } |
|
637 | + echo "<ul class='subsubsub'>\n"; |
|
638 | + foreach ($views as $view) { |
|
639 | + $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0; |
|
640 | + if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) { |
|
641 | + $filter = "<li"; |
|
642 | + $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : ''; |
|
643 | + $filter .= ">"; |
|
644 | + $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>'; |
|
645 | + $filter .= '<span class="count">(' . $count . ')</span>'; |
|
646 | + $filter .= '</li>'; |
|
647 | + $assembled_views[ $view['slug'] ] = $filter; |
|
648 | + } |
|
649 | + } |
|
650 | + |
|
651 | + echo ! empty($assembled_views) |
|
652 | + ? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views) |
|
653 | + : ''; |
|
654 | + echo "</ul>"; |
|
655 | + } |
|
656 | + |
|
657 | + |
|
658 | + /** |
|
659 | + * Generates content for a single row of the table |
|
660 | + * |
|
661 | + * @param EE_Base_Class $item The current item |
|
662 | + * @since 4.1 |
|
663 | + * @access public |
|
664 | + */ |
|
665 | + public function single_row($item) |
|
666 | + { |
|
667 | + $row_class = $this->_get_row_class($item); |
|
668 | + echo '<tr class="' . esc_attr($row_class) . '">'; |
|
669 | + $this->single_row_columns($item); // already escaped |
|
670 | + echo '</tr>'; |
|
671 | + } |
|
672 | + |
|
673 | + |
|
674 | + /** |
|
675 | + * This simply sets up the row class for the table rows. |
|
676 | + * Allows for easier overriding of child methods for setting up sorting. |
|
677 | + * |
|
678 | + * @param EE_Base_Class $item the current item |
|
679 | + * @return string |
|
680 | + */ |
|
681 | + protected function _get_row_class($item) |
|
682 | + { |
|
683 | + static $row_class = ''; |
|
684 | + $row_class = ($row_class === '' ? 'alternate' : ''); |
|
685 | + |
|
686 | + $new_row_class = $row_class; |
|
687 | + |
|
688 | + if (! empty($this->_ajax_sorting_callback)) { |
|
689 | + $new_row_class .= ' rowsortable'; |
|
690 | + } |
|
691 | + |
|
692 | + return $new_row_class; |
|
693 | + } |
|
694 | + |
|
695 | + |
|
696 | + /** |
|
697 | + * @return array |
|
698 | + */ |
|
699 | + public function get_sortable_columns() |
|
700 | + { |
|
701 | + return (array) $this->_sortable_columns; |
|
702 | + } |
|
703 | + |
|
704 | + |
|
705 | + /** |
|
706 | + * @return string |
|
707 | + */ |
|
708 | + public function get_ajax_sorting_callback() |
|
709 | + { |
|
710 | + return $this->_ajax_sorting_callback; |
|
711 | + } |
|
712 | + |
|
713 | + |
|
714 | + /** |
|
715 | + * @return array |
|
716 | + */ |
|
717 | + public function get_hidden_columns() |
|
718 | + { |
|
719 | + $user_id = get_current_user_id(); |
|
720 | + $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id); |
|
721 | + if (empty($has_default) && ! empty($this->_hidden_columns)) { |
|
722 | + update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true); |
|
723 | + update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true); |
|
724 | + } |
|
725 | + $ref = 'manage' . $this->screen->id . 'columnshidden'; |
|
726 | + return (array) get_user_option($ref, $user_id); |
|
727 | + } |
|
728 | + |
|
729 | + |
|
730 | + /** |
|
731 | + * Generates the columns for a single row of the table. |
|
732 | + * Overridden from wp_list_table so as to allow us to filter the column content for a given |
|
733 | + * column. |
|
734 | + * |
|
735 | + * @param EE_Base_Class $item The current item |
|
736 | + * @since 3.1.0 |
|
737 | + */ |
|
738 | + public function single_row_columns($item) |
|
739 | + { |
|
740 | + [$columns, $hidden, $sortable, $primary] = $this->get_column_info(); |
|
741 | + |
|
742 | + foreach ($columns as $column_name => $column_display_name) { |
|
743 | + |
|
744 | + /** |
|
745 | + * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns |
|
746 | + * are hidden or not instead of using "display:none;". This bit of code provides backward compat. |
|
747 | + */ |
|
748 | + $hidden_class = in_array($column_name, $hidden) ? ' hidden' : ''; |
|
749 | + |
|
750 | + $classes = $column_name . ' column-' . $column_name . $hidden_class; |
|
751 | + if ($primary === $column_name) { |
|
752 | + $classes .= ' has-row-actions column-primary'; |
|
753 | + } |
|
754 | + |
|
755 | + $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"'; |
|
756 | + |
|
757 | + $class = 'class="' . esc_attr($classes) . '"'; |
|
758 | + |
|
759 | + $attributes = "{$class}{$data}"; |
|
760 | + |
|
761 | + if ($column_name === 'cb') { |
|
762 | + echo '<th scope="row" class="check-column">'; |
|
763 | + echo apply_filters( |
|
764 | + 'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content', |
|
765 | + $this->column_cb($item), // already escaped |
|
766 | + $item, |
|
767 | + $this |
|
768 | + ); |
|
769 | + echo '</th>'; |
|
770 | + } elseif (method_exists($this, "column_$column_name")) { |
|
771 | + echo "<td $attributes>"; // already escaped |
|
772 | + echo apply_filters( |
|
773 | + 'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content', |
|
774 | + call_user_func([$this, "column_$column_name"], $item), |
|
775 | + $item, |
|
776 | + $this |
|
777 | + ); |
|
778 | + echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags()); |
|
779 | + echo "</td>"; |
|
780 | + } else { |
|
781 | + echo "<td $attributes>"; // already escaped |
|
782 | + echo apply_filters( |
|
783 | + 'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content', |
|
784 | + $this->column_default($item, $column_name), |
|
785 | + $item, |
|
786 | + $column_name, |
|
787 | + $this |
|
788 | + ); |
|
789 | + echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags()); |
|
790 | + echo "</td>"; |
|
791 | + } |
|
792 | + } |
|
793 | + } |
|
794 | + |
|
795 | + |
|
796 | + /** |
|
797 | + * Extra controls to be displayed between bulk actions and pagination |
|
798 | + * |
|
799 | + * @access public |
|
800 | + * @param string $which |
|
801 | + * @throws EE_Error |
|
802 | + */ |
|
803 | + public function extra_tablenav($which) |
|
804 | + { |
|
805 | + if ($which === 'top') { |
|
806 | + $this->_filters(); |
|
807 | + echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags()); |
|
808 | + } else { |
|
809 | + echo '<div class="list-table-bottom-buttons alignleft actions">'; |
|
810 | + foreach ($this->_bottom_buttons as $type => $action) { |
|
811 | + $route = $action['route'] ?? ''; |
|
812 | + $extra_request = $action['extra_request'] ?? ''; |
|
813 | + $btn_class = $action['btn_class'] ?? 'button button--secondary'; |
|
814 | + // already escaped |
|
815 | + echo wp_kses($this->_admin_page->get_action_link_or_button( |
|
816 | + $route, |
|
817 | + $type, |
|
818 | + $extra_request, |
|
819 | + $btn_class |
|
820 | + ), AllowedTags::getWithFormTags()); |
|
821 | + } |
|
822 | + do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen); |
|
823 | + echo '</div>'; |
|
824 | + } |
|
825 | + } |
|
826 | + |
|
827 | + |
|
828 | + /** |
|
829 | + * Get an associative array ( option_name => option_title ) with the list |
|
830 | + * of bulk actions available on this table. |
|
831 | + * |
|
832 | + * @return array |
|
833 | + * @since 3.1.0 |
|
834 | + * @access protected |
|
835 | + */ |
|
836 | + public function get_bulk_actions() |
|
837 | + { |
|
838 | + return (array) $this->_get_bulk_actions(); |
|
839 | + } |
|
840 | + |
|
841 | + |
|
842 | + /** |
|
843 | + * Processing bulk actions. |
|
844 | + */ |
|
845 | + public function process_bulk_action() |
|
846 | + { |
|
847 | + // this is not used it is handled by the child EE_Admin_Page class (routes). However, including here for |
|
848 | + // reference in case there is a case where it gets used. |
|
849 | + } |
|
850 | + |
|
851 | + |
|
852 | + /** |
|
853 | + * returns the EE admin page this list table is associated with |
|
854 | + * |
|
855 | + * @return EE_Admin_Page |
|
856 | + */ |
|
857 | + public function get_admin_page() |
|
858 | + { |
|
859 | + return $this->_admin_page; |
|
860 | + } |
|
861 | + |
|
862 | + |
|
863 | + /** |
|
864 | + * A "helper" function for all children to provide an html string of |
|
865 | + * actions to output in their content. It is preferable for child classes |
|
866 | + * to use this method for generating their actions content so that it's |
|
867 | + * filterable by plugins |
|
868 | + * |
|
869 | + * @param string $action_container what are the html container |
|
870 | + * elements for this actions string? |
|
871 | + * @param string $action_class What class is for the container |
|
872 | + * element. |
|
873 | + * @param string $action_items The contents for the action items |
|
874 | + * container. This is filtered before |
|
875 | + * returned. |
|
876 | + * @param string $action_id What id (optional) is used for the |
|
877 | + * container element. |
|
878 | + * @param EE_Base_Class $item The object for the column displaying |
|
879 | + * the actions. |
|
880 | + * @return string The assembled action elements container. |
|
881 | + */ |
|
882 | + protected function _action_string( |
|
883 | + $action_items, |
|
884 | + $item, |
|
885 | + $action_container = 'ul', |
|
886 | + $action_class = '', |
|
887 | + $action_id = '' |
|
888 | + ) { |
|
889 | + $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : ''; |
|
890 | + $action_id = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : ''; |
|
891 | + $open_tag = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : ''; |
|
892 | + $close_tag = ! empty($action_container) ? '</' . $action_container . '>' : ''; |
|
893 | + try { |
|
894 | + $content = apply_filters( |
|
895 | + 'FHEE__EE_Admin_List_Table___action_string__action_items', |
|
896 | + $action_items, |
|
897 | + $item, |
|
898 | + $this |
|
899 | + ); |
|
900 | + } catch (Exception $e) { |
|
901 | + if (WP_DEBUG) { |
|
902 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
903 | + } |
|
904 | + $content = $action_items; |
|
905 | + } |
|
906 | + return "{$open_tag}{$content}{$close_tag}"; |
|
907 | + } |
|
908 | + |
|
909 | + |
|
910 | + /** |
|
911 | + * @return string |
|
912 | + */ |
|
913 | + protected function getReturnUrl() |
|
914 | + { |
|
915 | + $host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST'); |
|
916 | + $uri = $this->_admin_page->get_request()->getServerParam('REQUEST_URI'); |
|
917 | + return urlencode(esc_url_raw("//{$host}{$uri}")); |
|
918 | + } |
|
919 | + |
|
920 | + |
|
921 | + /** |
|
922 | + * @param string $id |
|
923 | + * @param string $content |
|
924 | + * @param string $align start (default), center, end |
|
925 | + * @return string |
|
926 | + * @since 5.0.0.p |
|
927 | + */ |
|
928 | + protected function columnContent($id, $content, $align = 'start') |
|
929 | + { |
|
930 | + if (! isset($this->_columns[ $id ])) { |
|
931 | + throw new DomainException('missing column id'); |
|
932 | + } |
|
933 | + $heading = $id !== 'cb' ? $this->_columns[ $id ] : ''; |
|
934 | + $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start'; |
|
935 | + $align = "ee-responsive-table-cell--{$align}"; |
|
936 | + |
|
937 | + $html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>"; |
|
938 | + $html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>"; |
|
939 | + $html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>"; |
|
940 | + $html .= "</div>"; |
|
941 | + return $html; |
|
942 | + } |
|
943 | + |
|
944 | + |
|
945 | + protected function actionsModalMenu($actions): string |
|
946 | + { |
|
947 | + return ' |
|
948 | 948 | <div class="ee-modal-menu"> |
949 | 949 | <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip" |
950 | 950 | aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '" |
@@ -956,43 +956,43 @@ discard block |
||
956 | 956 | ' . $actions . ' |
957 | 957 | </div> |
958 | 958 | </div>'; |
959 | - } |
|
959 | + } |
|
960 | 960 | |
961 | 961 | |
962 | - public function actionsColumnHeader(): string |
|
963 | - { |
|
964 | - return ' |
|
962 | + public function actionsColumnHeader(): string |
|
963 | + { |
|
964 | + return ' |
|
965 | 965 | <span class="ee-actions-column-header-wrap"> |
966 | 966 | <span class="dashicons dashicons-screenoptions"></span> |
967 | 967 | <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span> |
968 | 968 | </span>'; |
969 | - } |
|
970 | - |
|
971 | - |
|
972 | - protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string |
|
973 | - { |
|
974 | - $class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action'; |
|
975 | - $class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class; |
|
976 | - $label = ! empty($label) ? " aria-label='{$label}'" : ''; |
|
977 | - return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>"; |
|
978 | - } |
|
979 | - |
|
980 | - /** |
|
981 | - * Override the search box method of WP List Table to include a reset button |
|
982 | - * |
|
983 | - * @param string $text The 'submit' button label. |
|
984 | - * @param string $input_id ID attribute value for the search input field. |
|
985 | - */ |
|
986 | - public function search_box($text, $input_id) |
|
987 | - { |
|
988 | - if (empty($_REQUEST['s']) && ! $this->has_items()) { |
|
989 | - return; |
|
990 | - } |
|
991 | - |
|
992 | - $this->admin_list_table_filters->searchBox( |
|
993 | - $text, |
|
994 | - $input_id, |
|
995 | - $this->get_admin_page()->get_current_page_view_url() |
|
996 | - ); |
|
997 | - } |
|
969 | + } |
|
970 | + |
|
971 | + |
|
972 | + protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string |
|
973 | + { |
|
974 | + $class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action'; |
|
975 | + $class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class; |
|
976 | + $label = ! empty($label) ? " aria-label='{$label}'" : ''; |
|
977 | + return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>"; |
|
978 | + } |
|
979 | + |
|
980 | + /** |
|
981 | + * Override the search box method of WP List Table to include a reset button |
|
982 | + * |
|
983 | + * @param string $text The 'submit' button label. |
|
984 | + * @param string $input_id ID attribute value for the search input field. |
|
985 | + */ |
|
986 | + public function search_box($text, $input_id) |
|
987 | + { |
|
988 | + if (empty($_REQUEST['s']) && ! $this->has_items()) { |
|
989 | + return; |
|
990 | + } |
|
991 | + |
|
992 | + $this->admin_list_table_filters->searchBox( |
|
993 | + $text, |
|
994 | + $input_id, |
|
995 | + $this->get_admin_page()->get_current_page_view_url() |
|
996 | + ); |
|
997 | + } |
|
998 | 998 | } |
@@ -18,497 +18,497 @@ |
||
18 | 18 | */ |
19 | 19 | abstract class EE_Admin_Page_Init extends EE_Base |
20 | 20 | { |
21 | - // identity properties (set in _set_defaults and _set_init_properties) |
|
22 | - public $label; |
|
21 | + // identity properties (set in _set_defaults and _set_init_properties) |
|
22 | + public $label; |
|
23 | 23 | |
24 | - /** |
|
25 | - * Menu map has a capability. However, this allows admin pages to have separate capability requirements for menus |
|
26 | - * and accessing pages. If capability is NOT set, then it defaults to the menu_map capability. |
|
27 | - * |
|
28 | - * @var string |
|
29 | - */ |
|
30 | - public $capability; |
|
24 | + /** |
|
25 | + * Menu map has a capability. However, this allows admin pages to have separate capability requirements for menus |
|
26 | + * and accessing pages. If capability is NOT set, then it defaults to the menu_map capability. |
|
27 | + * |
|
28 | + * @var string |
|
29 | + */ |
|
30 | + public $capability; |
|
31 | 31 | |
32 | 32 | |
33 | - /** |
|
34 | - * This holds the menu map object for this admin page. |
|
35 | - * |
|
36 | - * @var AdminMenuItem |
|
37 | - */ |
|
38 | - protected $_menu_map = null; |
|
39 | - |
|
40 | - /** |
|
41 | - * deprecated |
|
42 | - */ |
|
43 | - public $menu_label; |
|
44 | - |
|
45 | - public $menu_slug; |
|
46 | - |
|
47 | - |
|
48 | - // set in _set_defaults |
|
49 | - protected $_folder_name; |
|
50 | - |
|
51 | - protected $_folder_path; |
|
52 | - |
|
53 | - protected $_file_name; |
|
54 | - |
|
55 | - public $hook_file; |
|
56 | - |
|
57 | - protected $_wp_page_slug; |
|
58 | - |
|
59 | - protected $_routing; |
|
60 | - |
|
61 | - |
|
62 | - /** |
|
63 | - * This holds the page object. |
|
64 | - * |
|
65 | - * @var EE_Admin_Page |
|
66 | - */ |
|
67 | - protected $_loaded_page_object; |
|
68 | - |
|
69 | - |
|
70 | - // for caf |
|
71 | - protected $_files_hooked; |
|
72 | - |
|
73 | - protected $_hook_paths; |
|
74 | - |
|
75 | - // load_page? |
|
76 | - private $_load_page; |
|
77 | - |
|
78 | - /** |
|
79 | - * @var LoaderInterface |
|
80 | - */ |
|
81 | - protected $loader; |
|
82 | - |
|
83 | - /** |
|
84 | - * @var RequestInterface |
|
85 | - */ |
|
86 | - protected $request; |
|
87 | - |
|
88 | - |
|
89 | - /** |
|
90 | - * @throws InvalidArgumentException |
|
91 | - * @throws InvalidDataTypeException |
|
92 | - * @throws InvalidInterfaceException |
|
93 | - */ |
|
94 | - public function __construct(RequestInterface $request = null) |
|
95 | - { |
|
96 | - $this->loader = LoaderFactory::getLoader(); |
|
97 | - $this->request = $request instanceof RequestInterface |
|
98 | - ? $request |
|
99 | - : $this->loader->getShared(RequestInterface::class); |
|
100 | - // set global defaults |
|
101 | - $this->_set_defaults(); |
|
102 | - // set properties that are always available with objects. |
|
103 | - $this->_set_init_properties(); |
|
104 | - // global styles/scripts across all wp admin pages |
|
105 | - add_action('admin_enqueue_scripts', [$this, 'load_wp_global_scripts_styles'], 5); |
|
106 | - // load initial stuff. |
|
107 | - $this->_set_file_and_folder_name(); |
|
108 | - } |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * _set_init_properties |
|
113 | - * Child classes use to set the following properties: |
|
114 | - * $label |
|
115 | - * |
|
116 | - * @abstract |
|
117 | - * @return void |
|
118 | - */ |
|
119 | - abstract protected function _set_init_properties(); |
|
120 | - |
|
121 | - |
|
122 | - /** |
|
123 | - * @return AdminMenuItem|null |
|
124 | - * @since 4.4.0 |
|
125 | - * @deprecated 5.0.0.p |
|
126 | - */ |
|
127 | - public function get_menu_map() |
|
128 | - { |
|
129 | - return $this->adminMenu(); |
|
130 | - } |
|
131 | - |
|
132 | - |
|
133 | - /** |
|
134 | - * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of |
|
135 | - * EE_Admin_Page_Menu_Map. Their menu can either be EE_Admin_Page_Main_Menu or AdminMenuSubItem. |
|
136 | - * |
|
137 | - * @since 4.4.0 |
|
138 | - * @deprecated 5.0.0.p |
|
139 | - */ |
|
140 | - protected function _set_menu_map() |
|
141 | - { |
|
142 | - $this->_menu_map = null; |
|
143 | - } |
|
144 | - |
|
145 | - |
|
146 | - /** |
|
147 | - * @since 5.0.0.p |
|
148 | - */ |
|
149 | - public function setupLegacyAdminMenuItem() |
|
150 | - { |
|
151 | - // will be overridden by child classes not using new system |
|
152 | - $this->_set_menu_map(); |
|
153 | - } |
|
154 | - |
|
155 | - |
|
156 | - /** |
|
157 | - * Child classes should return an array of properties used to construct the AdminMenuItem |
|
158 | - * |
|
159 | - * @return array |
|
160 | - * @since 5.0.0.p |
|
161 | - */ |
|
162 | - public function getMenuProperties(): array |
|
163 | - { |
|
164 | - return []; |
|
165 | - } |
|
166 | - |
|
167 | - |
|
168 | - /** |
|
169 | - * @param AdminMenuItem $menu |
|
170 | - * @return void |
|
171 | - * @since 5.0.0.p |
|
172 | - */ |
|
173 | - public function setAdminMenu(AdminMenuItem $menu): void |
|
174 | - { |
|
175 | - $this->_menu_map = $menu; |
|
176 | - } |
|
177 | - |
|
178 | - |
|
179 | - /** |
|
180 | - * returns the menu map for this admin page |
|
181 | - * |
|
182 | - * @return AdminMenuItem|null |
|
183 | - * @since 5.0.0.p |
|
184 | - */ |
|
185 | - public function adminMenu(): ?AdminMenuItem |
|
186 | - { |
|
187 | - return $this->_menu_map; |
|
188 | - } |
|
189 | - |
|
190 | - |
|
191 | - /** |
|
192 | - * @param string $wp_page_slug |
|
193 | - * @since 5.0.0.p |
|
194 | - */ |
|
195 | - public function setWpPageSlug(string $wp_page_slug): void |
|
196 | - { |
|
197 | - $this->_wp_page_slug = $wp_page_slug; |
|
198 | - } |
|
199 | - |
|
200 | - |
|
201 | - /** |
|
202 | - * This loads scripts and styles for the EE_Admin system |
|
203 | - * that must be available on ALL WP admin pages (i.e. EE_menu items) |
|
204 | - * |
|
205 | - * @return void |
|
206 | - */ |
|
207 | - public function load_wp_global_scripts_styles() |
|
208 | - { |
|
209 | - wp_register_style( |
|
210 | - 'espresso_menu', |
|
211 | - EE_ADMIN_URL . 'assets/admin-menu-styles.css', |
|
212 | - ['dashicons'], |
|
213 | - EVENT_ESPRESSO_VERSION |
|
214 | - ); |
|
215 | - wp_enqueue_style('espresso_menu'); |
|
216 | - } |
|
217 | - |
|
218 | - |
|
219 | - /** |
|
220 | - * this sets default properties (might be overridden in _set_init_properties); |
|
221 | - * |
|
222 | - * @return void |
|
223 | - */ |
|
224 | - private function _set_defaults() |
|
225 | - { |
|
226 | - $this->_file_name = $this->_folder_name = $this->_wp_page_slug = $this->capability = null; |
|
227 | - $this->_routing = true; |
|
228 | - $this->_load_page = false; |
|
229 | - $this->_files_hooked = $this->_hook_paths = []; |
|
230 | - } |
|
231 | - |
|
232 | - |
|
233 | - public function setCapability($capability, $menu_slug) |
|
234 | - { |
|
235 | - $this->capability = apply_filters('FHEE_' . $menu_slug . '_capability', $capability); |
|
236 | - } |
|
237 | - |
|
238 | - |
|
239 | - /** |
|
240 | - * @deprecated 5.0.0.p |
|
241 | - */ |
|
242 | - protected function _set_capability() |
|
243 | - { |
|
244 | - if ($this->_menu_map instanceof AdminMenuItem) { |
|
245 | - $this->setCapability($this->_menu_map->capability(), $this->_menu_map->menuSlug()); |
|
246 | - } |
|
247 | - } |
|
248 | - |
|
249 | - |
|
250 | - /** |
|
251 | - * initialize_admin_page |
|
252 | - * This method is what executes the loading of the specific page class for the given dir_name as called by the |
|
253 | - * EE_Admin_Init class. |
|
254 | - * |
|
255 | - * @return void |
|
256 | - * @throws EE_Error |
|
257 | - * @throws ReflectionException |
|
258 | - */ |
|
259 | - public function initialize_admin_page() |
|
260 | - { |
|
261 | - // let's check user access first |
|
262 | - $this->_check_user_access(); |
|
263 | - if (! $this->_loaded_page_object instanceof EE_Admin_Page) { |
|
264 | - return; |
|
265 | - } |
|
266 | - $this->_loaded_page_object->route_admin_request(); |
|
267 | - } |
|
268 | - |
|
269 | - |
|
270 | - /** |
|
271 | - * @param string $wp_page_slug |
|
272 | - * @throws EE_Error |
|
273 | - */ |
|
274 | - public function set_page_dependencies(string $wp_page_slug) |
|
275 | - { |
|
276 | - if (! $this->_load_page) { |
|
277 | - return; |
|
278 | - } |
|
279 | - if (! $this->_loaded_page_object instanceof EE_Admin_Page) { |
|
280 | - $msg[] = esc_html__( |
|
281 | - 'We can\'t load the page because we\'re missing a valid page object that tells us what to load', |
|
282 | - 'event_espresso' |
|
283 | - ); |
|
284 | - $msg[] = $msg[0] . "\r\n" |
|
285 | - . sprintf( |
|
286 | - esc_html__( |
|
287 | - 'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory', |
|
288 | - 'event_espresso' |
|
289 | - ), |
|
290 | - $this->_file_name, |
|
291 | - $this->_file_name, |
|
292 | - $this->_folder_path . $this->_file_name, |
|
293 | - $this->_menu_map->menuSlug() |
|
294 | - ); |
|
295 | - throw new EE_Error(implode('||', $msg)); |
|
296 | - } |
|
297 | - $this->_loaded_page_object->set_wp_page_slug($wp_page_slug); |
|
298 | - $page_hook = "load-$wp_page_slug"; |
|
299 | - // hook into page load hook so all page specific stuff gets loaded. |
|
300 | - if (! empty($wp_page_slug)) { |
|
301 | - add_action($page_hook, [$this->_loaded_page_object, 'load_page_dependencies']); |
|
302 | - } |
|
303 | - } |
|
304 | - |
|
305 | - |
|
306 | - /** |
|
307 | - * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run |
|
308 | - * before the load-page... hook. Note, the page loads are happening around the wp_init hook. |
|
309 | - * |
|
310 | - * @return void |
|
311 | - * @throws InvalidArgumentException |
|
312 | - * @throws InvalidDataTypeException |
|
313 | - * @throws InvalidInterfaceException |
|
314 | - * @throws EE_Error |
|
315 | - * @throws ReflectionException |
|
316 | - */ |
|
317 | - public function do_initial_loads() |
|
318 | - { |
|
319 | - // no loading or initializing if menu map is setup incorrectly. |
|
320 | - if (! $this->_menu_map instanceof AdminMenuItem) { |
|
321 | - return; |
|
322 | - } |
|
323 | - $this->_initialize_admin_page(); |
|
324 | - } |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * all we're doing here is setting the $_file_name property for later use. |
|
329 | - * |
|
330 | - * @return void |
|
331 | - */ |
|
332 | - private function _set_file_and_folder_name() |
|
333 | - { |
|
334 | - $bt = debug_backtrace(); |
|
335 | - // for more reliable determination of folder name |
|
336 | - // we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this). Why? Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins) |
|
337 | - $class = get_class($this); |
|
338 | - foreach ($bt as $index => $values) { |
|
339 | - if (isset($values['class']) && $values['class'] == $class) { |
|
340 | - $file_index = $index - 1; |
|
341 | - $this->_folder_name = basename(dirname($bt[ $file_index ]['file'])); |
|
342 | - if (! empty($this->_folder_name)) { |
|
343 | - break; |
|
344 | - } |
|
345 | - } |
|
346 | - } |
|
347 | - $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/'; |
|
348 | - $this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name); |
|
349 | - $this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name)); |
|
350 | - $this->_file_name = str_replace(' ', '_', $this->_file_name); |
|
351 | - } |
|
352 | - |
|
353 | - |
|
354 | - /** |
|
355 | - * This automatically checks if we have a hook class in the loaded child directory. If we DO then we will register |
|
356 | - * it with the appropriate pages. That way all we have to do is make sure the file is named correctly and |
|
357 | - * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do: |
|
358 | - * events_Messages_Hooks.class.php |
|
359 | - * |
|
360 | - * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks |
|
361 | - * files/classes |
|
362 | - * @return array |
|
363 | - */ |
|
364 | - public function register_hooks(bool $extend = false): array |
|
365 | - { |
|
366 | - // get a list of files in the directory that have the "Hook" in their name an |
|
367 | - // if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property. Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf. |
|
368 | - if ($extend) { |
|
369 | - $hook_files_glob_path = apply_filters( |
|
370 | - 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend', |
|
371 | - EE_CORE_CAF_ADMIN_EXTEND |
|
372 | - . $this->_folder_name |
|
373 | - . '/*' |
|
374 | - . $this->_file_name |
|
375 | - . '_Hooks_Extend.class.php' |
|
376 | - ); |
|
377 | - $this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend); |
|
378 | - } |
|
379 | - // loop through decaf folders |
|
380 | - $hook_files_glob_path = apply_filters( |
|
381 | - 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path', |
|
382 | - $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php' |
|
383 | - ); |
|
384 | - $this->_hook_paths = array_merge( |
|
385 | - $this->_register_hook_files($hook_files_glob_path), |
|
386 | - $this->_hook_paths |
|
387 | - ); // making sure any extended hook paths are later in the array than the core hook paths! |
|
388 | - return $this->_hook_paths; |
|
389 | - } |
|
390 | - |
|
391 | - |
|
392 | - protected function _register_hook_files($hook_files_glob_path, $extend = false): array |
|
393 | - { |
|
394 | - $hook_paths = glob($hook_files_glob_path); |
|
395 | - if (empty($hook_paths)) { |
|
396 | - return []; |
|
397 | - } |
|
398 | - foreach ($hook_paths as $file) { |
|
399 | - // lets get the linked admin. |
|
400 | - $hook_file = $extend |
|
401 | - ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file) |
|
402 | - : str_replace($this->_folder_path, '', $file); |
|
403 | - $replace = $extend |
|
404 | - ? '_' . $this->_file_name . '_Hooks_Extend.class.php' |
|
405 | - : '_' . $this->_file_name . '_Hooks.class.php'; |
|
406 | - $rel_admin = str_replace($replace, '', $hook_file); |
|
407 | - $rel_admin = strtolower($rel_admin); |
|
408 | - // make sure we haven't already got a hook setup for this page path |
|
409 | - if (in_array($rel_admin, $this->_files_hooked)) { |
|
410 | - continue; |
|
411 | - } |
|
412 | - require_once $file; |
|
413 | - $this->hook_file = $hook_file; |
|
414 | - $rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin; |
|
415 | - add_filter($rel_admin_hook, [$this, 'load_admin_hook']); |
|
416 | - $this->_files_hooked[] = $rel_admin; |
|
417 | - } |
|
418 | - return $hook_paths; |
|
419 | - } |
|
420 | - |
|
421 | - |
|
422 | - public function load_admin_hook($registered_pages) |
|
423 | - { |
|
424 | - return array_merge((array) $this->hook_file, $registered_pages); |
|
425 | - } |
|
426 | - |
|
427 | - |
|
428 | - /** |
|
429 | - * _initialize_admin_page |
|
430 | - * |
|
431 | - * @throws EE_Error |
|
432 | - * @throws ReflectionException |
|
433 | - * @see initialize_admin_page() for info |
|
434 | - */ |
|
435 | - protected function _initialize_admin_page() |
|
436 | - { |
|
437 | - // JUST CHECK WE'RE ON RIGHT PAGE. |
|
438 | - $page = $this->request->getRequestParam('page'); |
|
439 | - $page = $this->request->getRequestParam('current_page', $page); |
|
440 | - $menu_slug = $this->_menu_map->menuSlug(); |
|
441 | - |
|
442 | - |
|
443 | - if ($this->_routing && ($page === '' || $page !== $menu_slug)) { |
|
444 | - // not on the right page so let's get out. |
|
445 | - return; |
|
446 | - } |
|
447 | - $this->_load_page = true; |
|
448 | - |
|
449 | - // we don't need to do a page_request check here because it's only called via WP menu system. |
|
450 | - $admin_page = $this->_file_name . '_Admin_Page'; |
|
451 | - $hook_suffix = "{$menu_slug}_$admin_page"; |
|
452 | - $admin_page = apply_filters( |
|
453 | - "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__$hook_suffix", |
|
454 | - $admin_page |
|
455 | - ); |
|
456 | - if (empty($admin_page)) { |
|
457 | - return; |
|
458 | - } |
|
459 | - // define requested admin page class name then load the file and instantiate |
|
460 | - $path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path . $admin_page . '.core.php'); |
|
461 | - // so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be: |
|
462 | - // FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page |
|
463 | - $path_to_file = apply_filters( |
|
464 | - "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__$hook_suffix", |
|
465 | - $path_to_file |
|
466 | - ); |
|
467 | - if (! is_readable($path_to_file)) { |
|
468 | - return; |
|
469 | - } |
|
470 | - // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place |
|
471 | - do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization'); |
|
472 | - do_action("AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_$menu_slug"); |
|
473 | - require_once($path_to_file); |
|
474 | - $this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]); |
|
475 | - $this->_loaded_page_object->initializePage(); |
|
476 | - |
|
477 | - do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization'); |
|
478 | - do_action("AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_$menu_slug"); |
|
479 | - } |
|
480 | - |
|
481 | - |
|
482 | - public function get_admin_page_name(): string |
|
483 | - { |
|
484 | - return $this->_file_name . '_Admin_Page'; |
|
485 | - } |
|
486 | - |
|
487 | - |
|
488 | - /** |
|
489 | - * @return EE_Admin_Page|null |
|
490 | - */ |
|
491 | - public function loaded_page_object(): ?EE_Admin_Page |
|
492 | - { |
|
493 | - return $this->_loaded_page_object; |
|
494 | - } |
|
495 | - |
|
496 | - |
|
497 | - /** |
|
498 | - * _check_user_access |
|
499 | - * verifies user access for this admin page. If no user access is available then let's gracefully exit with a |
|
500 | - * WordPress die message. |
|
501 | - * |
|
502 | - * @return void wp_die if fail |
|
503 | - */ |
|
504 | - private function _check_user_access() |
|
505 | - { |
|
506 | - if (! $this->_menu_map->currentUserHasAccess()) { |
|
507 | - wp_die( |
|
508 | - esc_html__('You don\'t have access to this page.', 'event_espresso'), |
|
509 | - '', |
|
510 | - ['back_link' => true] |
|
511 | - ); |
|
512 | - } |
|
513 | - } |
|
33 | + /** |
|
34 | + * This holds the menu map object for this admin page. |
|
35 | + * |
|
36 | + * @var AdminMenuItem |
|
37 | + */ |
|
38 | + protected $_menu_map = null; |
|
39 | + |
|
40 | + /** |
|
41 | + * deprecated |
|
42 | + */ |
|
43 | + public $menu_label; |
|
44 | + |
|
45 | + public $menu_slug; |
|
46 | + |
|
47 | + |
|
48 | + // set in _set_defaults |
|
49 | + protected $_folder_name; |
|
50 | + |
|
51 | + protected $_folder_path; |
|
52 | + |
|
53 | + protected $_file_name; |
|
54 | + |
|
55 | + public $hook_file; |
|
56 | + |
|
57 | + protected $_wp_page_slug; |
|
58 | + |
|
59 | + protected $_routing; |
|
60 | + |
|
61 | + |
|
62 | + /** |
|
63 | + * This holds the page object. |
|
64 | + * |
|
65 | + * @var EE_Admin_Page |
|
66 | + */ |
|
67 | + protected $_loaded_page_object; |
|
68 | + |
|
69 | + |
|
70 | + // for caf |
|
71 | + protected $_files_hooked; |
|
72 | + |
|
73 | + protected $_hook_paths; |
|
74 | + |
|
75 | + // load_page? |
|
76 | + private $_load_page; |
|
77 | + |
|
78 | + /** |
|
79 | + * @var LoaderInterface |
|
80 | + */ |
|
81 | + protected $loader; |
|
82 | + |
|
83 | + /** |
|
84 | + * @var RequestInterface |
|
85 | + */ |
|
86 | + protected $request; |
|
87 | + |
|
88 | + |
|
89 | + /** |
|
90 | + * @throws InvalidArgumentException |
|
91 | + * @throws InvalidDataTypeException |
|
92 | + * @throws InvalidInterfaceException |
|
93 | + */ |
|
94 | + public function __construct(RequestInterface $request = null) |
|
95 | + { |
|
96 | + $this->loader = LoaderFactory::getLoader(); |
|
97 | + $this->request = $request instanceof RequestInterface |
|
98 | + ? $request |
|
99 | + : $this->loader->getShared(RequestInterface::class); |
|
100 | + // set global defaults |
|
101 | + $this->_set_defaults(); |
|
102 | + // set properties that are always available with objects. |
|
103 | + $this->_set_init_properties(); |
|
104 | + // global styles/scripts across all wp admin pages |
|
105 | + add_action('admin_enqueue_scripts', [$this, 'load_wp_global_scripts_styles'], 5); |
|
106 | + // load initial stuff. |
|
107 | + $this->_set_file_and_folder_name(); |
|
108 | + } |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * _set_init_properties |
|
113 | + * Child classes use to set the following properties: |
|
114 | + * $label |
|
115 | + * |
|
116 | + * @abstract |
|
117 | + * @return void |
|
118 | + */ |
|
119 | + abstract protected function _set_init_properties(); |
|
120 | + |
|
121 | + |
|
122 | + /** |
|
123 | + * @return AdminMenuItem|null |
|
124 | + * @since 4.4.0 |
|
125 | + * @deprecated 5.0.0.p |
|
126 | + */ |
|
127 | + public function get_menu_map() |
|
128 | + { |
|
129 | + return $this->adminMenu(); |
|
130 | + } |
|
131 | + |
|
132 | + |
|
133 | + /** |
|
134 | + * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of |
|
135 | + * EE_Admin_Page_Menu_Map. Their menu can either be EE_Admin_Page_Main_Menu or AdminMenuSubItem. |
|
136 | + * |
|
137 | + * @since 4.4.0 |
|
138 | + * @deprecated 5.0.0.p |
|
139 | + */ |
|
140 | + protected function _set_menu_map() |
|
141 | + { |
|
142 | + $this->_menu_map = null; |
|
143 | + } |
|
144 | + |
|
145 | + |
|
146 | + /** |
|
147 | + * @since 5.0.0.p |
|
148 | + */ |
|
149 | + public function setupLegacyAdminMenuItem() |
|
150 | + { |
|
151 | + // will be overridden by child classes not using new system |
|
152 | + $this->_set_menu_map(); |
|
153 | + } |
|
154 | + |
|
155 | + |
|
156 | + /** |
|
157 | + * Child classes should return an array of properties used to construct the AdminMenuItem |
|
158 | + * |
|
159 | + * @return array |
|
160 | + * @since 5.0.0.p |
|
161 | + */ |
|
162 | + public function getMenuProperties(): array |
|
163 | + { |
|
164 | + return []; |
|
165 | + } |
|
166 | + |
|
167 | + |
|
168 | + /** |
|
169 | + * @param AdminMenuItem $menu |
|
170 | + * @return void |
|
171 | + * @since 5.0.0.p |
|
172 | + */ |
|
173 | + public function setAdminMenu(AdminMenuItem $menu): void |
|
174 | + { |
|
175 | + $this->_menu_map = $menu; |
|
176 | + } |
|
177 | + |
|
178 | + |
|
179 | + /** |
|
180 | + * returns the menu map for this admin page |
|
181 | + * |
|
182 | + * @return AdminMenuItem|null |
|
183 | + * @since 5.0.0.p |
|
184 | + */ |
|
185 | + public function adminMenu(): ?AdminMenuItem |
|
186 | + { |
|
187 | + return $this->_menu_map; |
|
188 | + } |
|
189 | + |
|
190 | + |
|
191 | + /** |
|
192 | + * @param string $wp_page_slug |
|
193 | + * @since 5.0.0.p |
|
194 | + */ |
|
195 | + public function setWpPageSlug(string $wp_page_slug): void |
|
196 | + { |
|
197 | + $this->_wp_page_slug = $wp_page_slug; |
|
198 | + } |
|
199 | + |
|
200 | + |
|
201 | + /** |
|
202 | + * This loads scripts and styles for the EE_Admin system |
|
203 | + * that must be available on ALL WP admin pages (i.e. EE_menu items) |
|
204 | + * |
|
205 | + * @return void |
|
206 | + */ |
|
207 | + public function load_wp_global_scripts_styles() |
|
208 | + { |
|
209 | + wp_register_style( |
|
210 | + 'espresso_menu', |
|
211 | + EE_ADMIN_URL . 'assets/admin-menu-styles.css', |
|
212 | + ['dashicons'], |
|
213 | + EVENT_ESPRESSO_VERSION |
|
214 | + ); |
|
215 | + wp_enqueue_style('espresso_menu'); |
|
216 | + } |
|
217 | + |
|
218 | + |
|
219 | + /** |
|
220 | + * this sets default properties (might be overridden in _set_init_properties); |
|
221 | + * |
|
222 | + * @return void |
|
223 | + */ |
|
224 | + private function _set_defaults() |
|
225 | + { |
|
226 | + $this->_file_name = $this->_folder_name = $this->_wp_page_slug = $this->capability = null; |
|
227 | + $this->_routing = true; |
|
228 | + $this->_load_page = false; |
|
229 | + $this->_files_hooked = $this->_hook_paths = []; |
|
230 | + } |
|
231 | + |
|
232 | + |
|
233 | + public function setCapability($capability, $menu_slug) |
|
234 | + { |
|
235 | + $this->capability = apply_filters('FHEE_' . $menu_slug . '_capability', $capability); |
|
236 | + } |
|
237 | + |
|
238 | + |
|
239 | + /** |
|
240 | + * @deprecated 5.0.0.p |
|
241 | + */ |
|
242 | + protected function _set_capability() |
|
243 | + { |
|
244 | + if ($this->_menu_map instanceof AdminMenuItem) { |
|
245 | + $this->setCapability($this->_menu_map->capability(), $this->_menu_map->menuSlug()); |
|
246 | + } |
|
247 | + } |
|
248 | + |
|
249 | + |
|
250 | + /** |
|
251 | + * initialize_admin_page |
|
252 | + * This method is what executes the loading of the specific page class for the given dir_name as called by the |
|
253 | + * EE_Admin_Init class. |
|
254 | + * |
|
255 | + * @return void |
|
256 | + * @throws EE_Error |
|
257 | + * @throws ReflectionException |
|
258 | + */ |
|
259 | + public function initialize_admin_page() |
|
260 | + { |
|
261 | + // let's check user access first |
|
262 | + $this->_check_user_access(); |
|
263 | + if (! $this->_loaded_page_object instanceof EE_Admin_Page) { |
|
264 | + return; |
|
265 | + } |
|
266 | + $this->_loaded_page_object->route_admin_request(); |
|
267 | + } |
|
268 | + |
|
269 | + |
|
270 | + /** |
|
271 | + * @param string $wp_page_slug |
|
272 | + * @throws EE_Error |
|
273 | + */ |
|
274 | + public function set_page_dependencies(string $wp_page_slug) |
|
275 | + { |
|
276 | + if (! $this->_load_page) { |
|
277 | + return; |
|
278 | + } |
|
279 | + if (! $this->_loaded_page_object instanceof EE_Admin_Page) { |
|
280 | + $msg[] = esc_html__( |
|
281 | + 'We can\'t load the page because we\'re missing a valid page object that tells us what to load', |
|
282 | + 'event_espresso' |
|
283 | + ); |
|
284 | + $msg[] = $msg[0] . "\r\n" |
|
285 | + . sprintf( |
|
286 | + esc_html__( |
|
287 | + 'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory', |
|
288 | + 'event_espresso' |
|
289 | + ), |
|
290 | + $this->_file_name, |
|
291 | + $this->_file_name, |
|
292 | + $this->_folder_path . $this->_file_name, |
|
293 | + $this->_menu_map->menuSlug() |
|
294 | + ); |
|
295 | + throw new EE_Error(implode('||', $msg)); |
|
296 | + } |
|
297 | + $this->_loaded_page_object->set_wp_page_slug($wp_page_slug); |
|
298 | + $page_hook = "load-$wp_page_slug"; |
|
299 | + // hook into page load hook so all page specific stuff gets loaded. |
|
300 | + if (! empty($wp_page_slug)) { |
|
301 | + add_action($page_hook, [$this->_loaded_page_object, 'load_page_dependencies']); |
|
302 | + } |
|
303 | + } |
|
304 | + |
|
305 | + |
|
306 | + /** |
|
307 | + * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run |
|
308 | + * before the load-page... hook. Note, the page loads are happening around the wp_init hook. |
|
309 | + * |
|
310 | + * @return void |
|
311 | + * @throws InvalidArgumentException |
|
312 | + * @throws InvalidDataTypeException |
|
313 | + * @throws InvalidInterfaceException |
|
314 | + * @throws EE_Error |
|
315 | + * @throws ReflectionException |
|
316 | + */ |
|
317 | + public function do_initial_loads() |
|
318 | + { |
|
319 | + // no loading or initializing if menu map is setup incorrectly. |
|
320 | + if (! $this->_menu_map instanceof AdminMenuItem) { |
|
321 | + return; |
|
322 | + } |
|
323 | + $this->_initialize_admin_page(); |
|
324 | + } |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * all we're doing here is setting the $_file_name property for later use. |
|
329 | + * |
|
330 | + * @return void |
|
331 | + */ |
|
332 | + private function _set_file_and_folder_name() |
|
333 | + { |
|
334 | + $bt = debug_backtrace(); |
|
335 | + // for more reliable determination of folder name |
|
336 | + // we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this). Why? Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins) |
|
337 | + $class = get_class($this); |
|
338 | + foreach ($bt as $index => $values) { |
|
339 | + if (isset($values['class']) && $values['class'] == $class) { |
|
340 | + $file_index = $index - 1; |
|
341 | + $this->_folder_name = basename(dirname($bt[ $file_index ]['file'])); |
|
342 | + if (! empty($this->_folder_name)) { |
|
343 | + break; |
|
344 | + } |
|
345 | + } |
|
346 | + } |
|
347 | + $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/'; |
|
348 | + $this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name); |
|
349 | + $this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name)); |
|
350 | + $this->_file_name = str_replace(' ', '_', $this->_file_name); |
|
351 | + } |
|
352 | + |
|
353 | + |
|
354 | + /** |
|
355 | + * This automatically checks if we have a hook class in the loaded child directory. If we DO then we will register |
|
356 | + * it with the appropriate pages. That way all we have to do is make sure the file is named correctly and |
|
357 | + * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do: |
|
358 | + * events_Messages_Hooks.class.php |
|
359 | + * |
|
360 | + * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks |
|
361 | + * files/classes |
|
362 | + * @return array |
|
363 | + */ |
|
364 | + public function register_hooks(bool $extend = false): array |
|
365 | + { |
|
366 | + // get a list of files in the directory that have the "Hook" in their name an |
|
367 | + // if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property. Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf. |
|
368 | + if ($extend) { |
|
369 | + $hook_files_glob_path = apply_filters( |
|
370 | + 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend', |
|
371 | + EE_CORE_CAF_ADMIN_EXTEND |
|
372 | + . $this->_folder_name |
|
373 | + . '/*' |
|
374 | + . $this->_file_name |
|
375 | + . '_Hooks_Extend.class.php' |
|
376 | + ); |
|
377 | + $this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend); |
|
378 | + } |
|
379 | + // loop through decaf folders |
|
380 | + $hook_files_glob_path = apply_filters( |
|
381 | + 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path', |
|
382 | + $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php' |
|
383 | + ); |
|
384 | + $this->_hook_paths = array_merge( |
|
385 | + $this->_register_hook_files($hook_files_glob_path), |
|
386 | + $this->_hook_paths |
|
387 | + ); // making sure any extended hook paths are later in the array than the core hook paths! |
|
388 | + return $this->_hook_paths; |
|
389 | + } |
|
390 | + |
|
391 | + |
|
392 | + protected function _register_hook_files($hook_files_glob_path, $extend = false): array |
|
393 | + { |
|
394 | + $hook_paths = glob($hook_files_glob_path); |
|
395 | + if (empty($hook_paths)) { |
|
396 | + return []; |
|
397 | + } |
|
398 | + foreach ($hook_paths as $file) { |
|
399 | + // lets get the linked admin. |
|
400 | + $hook_file = $extend |
|
401 | + ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file) |
|
402 | + : str_replace($this->_folder_path, '', $file); |
|
403 | + $replace = $extend |
|
404 | + ? '_' . $this->_file_name . '_Hooks_Extend.class.php' |
|
405 | + : '_' . $this->_file_name . '_Hooks.class.php'; |
|
406 | + $rel_admin = str_replace($replace, '', $hook_file); |
|
407 | + $rel_admin = strtolower($rel_admin); |
|
408 | + // make sure we haven't already got a hook setup for this page path |
|
409 | + if (in_array($rel_admin, $this->_files_hooked)) { |
|
410 | + continue; |
|
411 | + } |
|
412 | + require_once $file; |
|
413 | + $this->hook_file = $hook_file; |
|
414 | + $rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin; |
|
415 | + add_filter($rel_admin_hook, [$this, 'load_admin_hook']); |
|
416 | + $this->_files_hooked[] = $rel_admin; |
|
417 | + } |
|
418 | + return $hook_paths; |
|
419 | + } |
|
420 | + |
|
421 | + |
|
422 | + public function load_admin_hook($registered_pages) |
|
423 | + { |
|
424 | + return array_merge((array) $this->hook_file, $registered_pages); |
|
425 | + } |
|
426 | + |
|
427 | + |
|
428 | + /** |
|
429 | + * _initialize_admin_page |
|
430 | + * |
|
431 | + * @throws EE_Error |
|
432 | + * @throws ReflectionException |
|
433 | + * @see initialize_admin_page() for info |
|
434 | + */ |
|
435 | + protected function _initialize_admin_page() |
|
436 | + { |
|
437 | + // JUST CHECK WE'RE ON RIGHT PAGE. |
|
438 | + $page = $this->request->getRequestParam('page'); |
|
439 | + $page = $this->request->getRequestParam('current_page', $page); |
|
440 | + $menu_slug = $this->_menu_map->menuSlug(); |
|
441 | + |
|
442 | + |
|
443 | + if ($this->_routing && ($page === '' || $page !== $menu_slug)) { |
|
444 | + // not on the right page so let's get out. |
|
445 | + return; |
|
446 | + } |
|
447 | + $this->_load_page = true; |
|
448 | + |
|
449 | + // we don't need to do a page_request check here because it's only called via WP menu system. |
|
450 | + $admin_page = $this->_file_name . '_Admin_Page'; |
|
451 | + $hook_suffix = "{$menu_slug}_$admin_page"; |
|
452 | + $admin_page = apply_filters( |
|
453 | + "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__$hook_suffix", |
|
454 | + $admin_page |
|
455 | + ); |
|
456 | + if (empty($admin_page)) { |
|
457 | + return; |
|
458 | + } |
|
459 | + // define requested admin page class name then load the file and instantiate |
|
460 | + $path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path . $admin_page . '.core.php'); |
|
461 | + // so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be: |
|
462 | + // FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page |
|
463 | + $path_to_file = apply_filters( |
|
464 | + "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__$hook_suffix", |
|
465 | + $path_to_file |
|
466 | + ); |
|
467 | + if (! is_readable($path_to_file)) { |
|
468 | + return; |
|
469 | + } |
|
470 | + // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place |
|
471 | + do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization'); |
|
472 | + do_action("AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_$menu_slug"); |
|
473 | + require_once($path_to_file); |
|
474 | + $this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]); |
|
475 | + $this->_loaded_page_object->initializePage(); |
|
476 | + |
|
477 | + do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization'); |
|
478 | + do_action("AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_$menu_slug"); |
|
479 | + } |
|
480 | + |
|
481 | + |
|
482 | + public function get_admin_page_name(): string |
|
483 | + { |
|
484 | + return $this->_file_name . '_Admin_Page'; |
|
485 | + } |
|
486 | + |
|
487 | + |
|
488 | + /** |
|
489 | + * @return EE_Admin_Page|null |
|
490 | + */ |
|
491 | + public function loaded_page_object(): ?EE_Admin_Page |
|
492 | + { |
|
493 | + return $this->_loaded_page_object; |
|
494 | + } |
|
495 | + |
|
496 | + |
|
497 | + /** |
|
498 | + * _check_user_access |
|
499 | + * verifies user access for this admin page. If no user access is available then let's gracefully exit with a |
|
500 | + * WordPress die message. |
|
501 | + * |
|
502 | + * @return void wp_die if fail |
|
503 | + */ |
|
504 | + private function _check_user_access() |
|
505 | + { |
|
506 | + if (! $this->_menu_map->currentUserHasAccess()) { |
|
507 | + wp_die( |
|
508 | + esc_html__('You don\'t have access to this page.', 'event_espresso'), |
|
509 | + '', |
|
510 | + ['back_link' => true] |
|
511 | + ); |
|
512 | + } |
|
513 | + } |
|
514 | 514 | } |
@@ -12,12 +12,12 @@ |
||
12 | 12 | */ |
13 | 13 | class EE_Admin_Page_Main_Menu extends AdminMenuTopLevel |
14 | 14 | { |
15 | - /** |
|
16 | - * @return string |
|
17 | - * @deprecated 5.0.0.p |
|
18 | - */ |
|
19 | - protected function _add_menu_page() |
|
20 | - { |
|
21 | - return $this->registerMenuItem(); |
|
22 | - } |
|
15 | + /** |
|
16 | + * @return string |
|
17 | + * @deprecated 5.0.0.p |
|
18 | + */ |
|
19 | + protected function _add_menu_page() |
|
20 | + { |
|
21 | + return $this->registerMenuItem(); |
|
22 | + } |
|
23 | 23 | } |
@@ -12,49 +12,49 @@ |
||
12 | 12 | */ |
13 | 13 | abstract class EE_Admin_Page_Menu_Map extends AdminMenuItem |
14 | 14 | { |
15 | - const NONE = 0; |
|
16 | - |
|
17 | - const BLOG_ADMIN_ONLY = 1; |
|
18 | - |
|
19 | - const BLOG_AND_NETWORK_ADMIN = 2; |
|
20 | - |
|
21 | - const NETWORK_ADMIN_ONLY = 3; |
|
22 | - |
|
23 | - |
|
24 | - /** |
|
25 | - * @return string |
|
26 | - * @deprecated 5.0.0.p |
|
27 | - */ |
|
28 | - protected function _add_menu_page(): string |
|
29 | - { |
|
30 | - return $this->registerMenuItem(); |
|
31 | - } |
|
32 | - |
|
33 | - |
|
34 | - /** |
|
35 | - * @param boolean $network_admin whether this is being added to the network admin page or not |
|
36 | - * @deprecated 5.0.0.p |
|
37 | - * @since 4.4.0 |
|
38 | - */ |
|
39 | - public function add_menu_page(bool $network_admin = false) |
|
40 | - { |
|
41 | - $this->registerAdminMenuItem($network_admin); |
|
42 | - } |
|
43 | - |
|
44 | - |
|
45 | - public function __get(string $property) |
|
46 | - { |
|
47 | - // converts a property name like 'menu_slug' into 'menuSlug' |
|
48 | - $getter = lcfirst(ucwords($property, '_')); |
|
49 | - return method_exists($this, $getter) ? $this->{$getter}() : null; |
|
50 | - } |
|
51 | - |
|
52 | - public function __set(string $property, $value) |
|
53 | - { |
|
54 | - // converts a property name like 'menu_slug' into 'setMenuSlug' |
|
55 | - $setter = 'set' . ucwords($property, '_'); |
|
56 | - if (method_exists($this, $setter)) { |
|
57 | - $this->{$setter}($value); |
|
58 | - } |
|
59 | - } |
|
15 | + const NONE = 0; |
|
16 | + |
|
17 | + const BLOG_ADMIN_ONLY = 1; |
|
18 | + |
|
19 | + const BLOG_AND_NETWORK_ADMIN = 2; |
|
20 | + |
|
21 | + const NETWORK_ADMIN_ONLY = 3; |
|
22 | + |
|
23 | + |
|
24 | + /** |
|
25 | + * @return string |
|
26 | + * @deprecated 5.0.0.p |
|
27 | + */ |
|
28 | + protected function _add_menu_page(): string |
|
29 | + { |
|
30 | + return $this->registerMenuItem(); |
|
31 | + } |
|
32 | + |
|
33 | + |
|
34 | + /** |
|
35 | + * @param boolean $network_admin whether this is being added to the network admin page or not |
|
36 | + * @deprecated 5.0.0.p |
|
37 | + * @since 4.4.0 |
|
38 | + */ |
|
39 | + public function add_menu_page(bool $network_admin = false) |
|
40 | + { |
|
41 | + $this->registerAdminMenuItem($network_admin); |
|
42 | + } |
|
43 | + |
|
44 | + |
|
45 | + public function __get(string $property) |
|
46 | + { |
|
47 | + // converts a property name like 'menu_slug' into 'menuSlug' |
|
48 | + $getter = lcfirst(ucwords($property, '_')); |
|
49 | + return method_exists($this, $getter) ? $this->{$getter}() : null; |
|
50 | + } |
|
51 | + |
|
52 | + public function __set(string $property, $value) |
|
53 | + { |
|
54 | + // converts a property name like 'menu_slug' into 'setMenuSlug' |
|
55 | + $setter = 'set' . ucwords($property, '_'); |
|
56 | + if (method_exists($this, $setter)) { |
|
57 | + $this->{$setter}($value); |
|
58 | + } |
|
59 | + } |
|
60 | 60 | } |
@@ -12,12 +12,12 @@ |
||
12 | 12 | */ |
13 | 13 | class EE_Admin_Page_Sub_Menu extends AdminMenuSubItem |
14 | 14 | { |
15 | - /** |
|
16 | - * @return string |
|
17 | - * @deprecated 5.0.0.p |
|
18 | - */ |
|
19 | - protected function _add_menu_page() |
|
20 | - { |
|
21 | - return $this->registerMenuItem(); |
|
22 | - } |
|
15 | + /** |
|
16 | + * @return string |
|
17 | + * @deprecated 5.0.0.p |
|
18 | + */ |
|
19 | + protected function _add_menu_page() |
|
20 | + { |
|
21 | + return $this->registerMenuItem(); |
|
22 | + } |
|
23 | 23 | } |
@@ -10,22 +10,22 @@ |
||
10 | 10 | */ |
11 | 11 | class EE_Admin_Page_Menu_Group extends AdminMenuGroup |
12 | 12 | { |
13 | - /** |
|
14 | - * @return string |
|
15 | - * @deprecated 5.0.0.p |
|
16 | - */ |
|
17 | - protected function _add_menu_page(): string |
|
18 | - { |
|
19 | - return $this->registerMenuItem(); |
|
20 | - } |
|
13 | + /** |
|
14 | + * @return string |
|
15 | + * @deprecated 5.0.0.p |
|
16 | + */ |
|
17 | + protected function _add_menu_page(): string |
|
18 | + { |
|
19 | + return $this->registerMenuItem(); |
|
20 | + } |
|
21 | 21 | |
22 | 22 | |
23 | - /** |
|
24 | - * @return string |
|
25 | - * @deprecated 5.0.0.p |
|
26 | - */ |
|
27 | - private function _group_link(): string |
|
28 | - { |
|
29 | - return $this->groupLink(); |
|
30 | - } |
|
23 | + /** |
|
24 | + * @return string |
|
25 | + * @deprecated 5.0.0.p |
|
26 | + */ |
|
27 | + private function _group_link(): string |
|
28 | + { |
|
29 | + return $this->groupLink(); |
|
30 | + } |
|
31 | 31 | } |