Completed
Branch TASK-9118-extensions-page (04eaec)
by
unknown
38:06 queued 23:39
created

Extend_Events_Admin_Page   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 1143
Duplicated Lines 16.19 %

Coupling/Cohesion

Components 6
Dependencies 19
Metric Value
wmc 124
lcom 6
cbo 19
dl 185
loc 1143
rs 0.6314

38 Methods

Rating   Name   Duplication   Size   Complexity  
A _add_screen_options_ticket_list_table() 0 3 1
A add_additional_datetime_button() 0 3 1
A add_datetime_clone_button() 0 3 1
A datetime_timezones_template() 0 3 1
A _set_list_table_views_category_list() 0 4 1
A _sample_export_file() 0 4 1
A list_table_filters() 0 19 4
A _tickets_overview_list_table() 0 4 1
A __construct() 0 6 1
C _extend_page_config() 0 174 7
A admin_init() 0 13 1
A heartbeat_response() 0 11 2
A extra_permalink_field_buttons() 0 10 2
A _set_list_table_views_ticket_list_table() 21 21 1
A load_scripts_styles_edit() 0 14 1
B _set_list_table_views_default() 0 35 3
A extra_list_table_actions() 11 11 2
A additional_legend_items() 0 10 2
D _duplicate_event() 14 153 18
A _import_page() 0 15 1
A _import_events() 0 6 1
B _events_export() 0 23 4
A _categories_export() 19 19 2
A _template_settings() 12 12 1
B _update_template_settings() 0 26 3
A _premium_event_editor_meta_boxes() 0 15 1
A registration_options_meta_box() 0 18 1
A event_type_meta_box() 0 5 1
C wp_terms_radio() 0 62 10
B espresso_event_months_dropdown() 0 14 6
A active_status_dropdown() 0 7 1
A category_dropdown() 0 5 2
A total_events_today() 0 11 1
A total_events_this_month() 0 15 1
F get_default_tickets() 64 64 15
C _trash_or_restore_ticket() 26 40 13
C _delete_ticket() 18 36 8
A _delete_the_ticket() 0 7 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Extend_Events_Admin_Page often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Extend_Events_Admin_Page, and based on these observations, apply Extract Interface, too.

1
<?php
2
if (!defined('EVENT_ESPRESSO_VERSION') )
3
	exit('NO direct script access allowed');
4
5
/**
6
 * Event Espresso
7
 *
8
 * Event Registration and Management Plugin for Wordpress
9
 *
10
 * @package		Event Espresso
11
 * @author		Seth Shoultes
12
 * @copyright	(c)2009-2012 Event Espresso All Rights Reserved.
13
 * @license		http://eventespresso.com/support/terms-conditions/  ** see Plugin Licensing **
14
 * @link		http://www.eventespresso.com
15
 * @version		4.0
16
 *
17
 * ------------------------------------------------------------------------
18
 *
19
 * Extend_Events_Admin_Page
20
 *
21
 * This is the Events Caffeinated admin page.
22
 *
23
 *
24
 * @package		Extend_Events_Admin_Page
25
 * @subpackage	includes/core/admin/Extend_Events_Admin_Page.core.php
26
 * @author		Darren Ethier
27
 *
28
 * ------------------------------------------------------------------------
29
 */
30
class Extend_Events_Admin_Page extends Events_Admin_Page {
31
32
33
	public function __construct( $routing = TRUE ) {
34
		parent::__construct( $routing );
35
		define( 'EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
36
		define( 'EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
37
		define( 'EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
38
	}
39
40
41
	protected function _extend_page_config() {
42
43
		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
44
		$default_espresso_boxes = $this->_default_espresso_metaboxes;
0 ignored issues
show
Unused Code introduced by
$default_espresso_boxes is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
45
46
		//is there a evt_id in the request?
47
		$evt_id = ! empty( $this->_req_data['EVT_ID'] ) && ! is_array( $this->_req_data['EVT_ID'] ) ? $this->_req_data['EVT_ID'] : 0;
48
		$evt_id = ! empty( $this->_req_data['post'] ) ? $this->_req_data['post'] : $evt_id;
49
50
		//tkt_id?
51
		$tkt_id = !empty( $this->_req_data['TKT_ID'] ) && ! is_array( $this->_req_data['TKT_ID'] ) ? $this->_req_data['TKT_ID'] : 0;
52
53
		$new_page_routes = array(
54
			'duplicate_event' => array(
55
				'func' => '_duplicate_event',
56
				'capability' => 'ee_edit_event',
57
				'obj_id' => $evt_id,
58
				'noheader' => TRUE
59
				),
60
			'ticket_list_table' => array(
61
				'func' => '_tickets_overview_list_table',
62
				'capability' => 'ee_read_default_tickets'
63
				),
64
			'trash_ticket' => array(
65
				'func' => '_trash_or_restore_ticket',
66
				'capability' => 'ee_delete_default_ticket',
67
				'obj_id' => $tkt_id,
68
				'noheader' => TRUE,
69
				'args' => array( 'trash' => TRUE )
70
				),
71
			'trash_tickets' => array(
72
				'func' => '_trash_or_restore_ticket',
73
				'capability' => 'ee_delete_default_tickets',
74
				'noheader' => TRUE,
75
				'args' => array( 'trash' => TRUE )
76
				),
77
			'restore_ticket' => array(
78
				'func' => '_trash_or_restore_ticket',
79
				'capability' => 'ee_delete_default_ticket',
80
				'obj_id' => $tkt_id,
81
				'noheader' => TRUE
82
				),
83
			'restore_tickets' => array(
84
				'func' => '_trash_or_restore_ticket',
85
				'capability' => 'ee_delete_default_tickets',
86
				'noheader' => TRUE
87
				),
88
			'delete_ticket' => array(
89
				'func' => '_delete_ticket',
90
				'capability' => 'ee_delete_default_ticket',
91
				'obj_id' => $tkt_id,
92
				'noheader' => TRUE
93
				),
94
			'delete_tickets' => array(
95
				'func' => '_delete_ticket',
96
				'capability' => 'ee_delete_default_tickets',
97
				'noheader' => TRUE
98
				),
99
			'import_page'=> array(
100
				'func' => '_import_page',
101
				'capability' => 'import'
102
				),
103
			'import' => array(
104
				'func'=>'_import_events',
105
				'capability' => 'import',
106
				'noheader'=>TRUE,
107
				),
108
			'import_events' => array(
109
				'func'=>'_import_events',
110
				'capability' => 'import',
111
				'noheader'=>TRUE,
112
				),
113
			'export_events' => array(
114
				'func' => '_events_export',
115
				'capability' => 'export',
116
				'noheader' => true
117
			),
118
			'export_categories' => array(
119
				'func' => '_categories_export',
120
				'capability' => 'export',
121
				'noheader' => TRUE
122
				),
123
			'sample_export_file'=>array(
124
				'func'=>'_sample_export_file',
125
				'capability' => 'export',
126
				'noheader'=>TRUE
127
				),
128
			'update_template_settings' => array(
129
				'func' => '_update_template_settings',
130
				'capability' => 'manage_options',
131
				'noheader' => true
132
				)
133
			);
134
135
		$this->_page_routes = array_merge( $this->_page_routes, $new_page_routes );
136
137
138
		//partial route/config override
139
		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
140
		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
141
		$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
142
		$this->_page_config['edit']['qtips'][] = 'EE_Event_Editor_Tips';
143
		$this->_page_config['edit']['metaboxes'][] = '_premium_event_editor_meta_boxes';
144
		$this->_page_config['default']['list_table'] = 'Extend_Events_Admin_List_Table';
145
146
		//add tickets tab but only if there are more than one default ticket!
147
		$tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(array( array('TKT_is_default' => 1 ) ), 'TKT_ID', TRUE );
148
		if ( $tkt_count > 1 ) {
149
			$new_page_config = array(
150
				'ticket_list_table' => array(
151
					'nav' => array(
152
						'label' => __('Default Tickets', 'event_espresso'),
153
						'order' => 60
154
						),
155
					'list_table' => 'Tickets_List_Table',
156
					'require_nonce' => FALSE
157
					)
158
				);
159
		}
160
161
		//template settings
162
		$new_page_config['template_settings'] = array(
0 ignored issues
show
Bug introduced by
The variable $new_page_config does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
163
			'nav' => array(
164
				'label' => __('Templates'),
165
				'order' => 30
166
			),
167
			'metaboxes' => array_merge( $this->_default_espresso_metaboxes, array( '_publish_post_box' ) ),
168
			'help_tabs' => array(
169
				'general_settings_templates_help_tab' => array(
170
					'title' => __('Templates', 'event_espresso'),
171
					'filename' => 'general_settings_templates'
172
				)
173
			),
174
			'help_tour' => array( 'Templates_Help_Tour' ),
175
			'require_nonce' => FALSE
176
		);
177
178
//		$new_page_config['import_page'] = array(
179
//				'nav' => array(
180
//					'label' => __('Import', 'event_espresso'),
181
//					'order' => 30
182
//				),
183
//				'help_tabs' => array(
184
//					'import_help_tab' => array(
185
//						'title' => __('Event Espresso Import', 'event_espresso'),
186
//						'filename' => 'import_page'
187
//						)
188
//					),
189
//				'help_tour' => array('Event_Import_Help_Tour'),
190
//				'metaboxes' => $default_espresso_boxes,
191
//				'require_nonce' => FALSE
192
//		);
193
		$this->_page_config = array_merge( $this->_page_config, $new_page_config );
194
195
		//add filters and actions
196
		//modifying _views
197
		add_filter('FHEE_event_datetime_metabox_add_additional_date_time_template', array( $this, 'add_additional_datetime_button' ), 10, 2 );
198
		add_filter('FHEE_event_datetime_metabox_clone_button_template', array( $this, 'add_datetime_clone_button' ), 10, 2 );
199
		add_filter('FHEE_event_datetime_metabox_timezones_template', array( $this, 'datetime_timezones_template'), 10, 2 );
200
201
202
		//filters for event list table
203
		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array( $this, 'list_table_filters'), 10, 2);
204
		add_filter('FHEE__Extend_Events_Admin_List_Table__column_actions__action_links', array( $this, 'extra_list_table_actions'), 10, 2 );
205
206
		//legend item
207
		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array( $this, 'additional_legend_items') );
208
209
		add_action('admin_init', array( $this, 'admin_init') );
210
211
		//heartbeat stuff
212
		add_filter( 'heartbeat_received', array( $this, 'heartbeat_response' ), 10, 2 );
213
214
	}
215
216
217
218
	/**
219
	 * admin_init
220
	 */
221
	public function admin_init() {
222
		EE_Registry::$i18n_js_strings = array_merge(
223
			EE_Registry::$i18n_js_strings,
224
			array(
225
				'image_confirm'          => __( 'Do you really want to delete this image? Please remember to update your event to complete the removal.', 'event_espresso' ),
226
				'event_starts_on'        => __( 'Event Starts on', 'event_espresso' ),
227
				'event_ends_on'          => __( 'Event Ends on', 'event_espresso' ),
228
				'event_datetime_actions' => __( 'Actions', 'event_espresso' ),
229
				'event_clone_dt_msg'     => __( 'Clone this Event Date and Time', 'event_espresso' ),
230
				'remove_event_dt_msg'    => __( 'Remove this Event Time', 'event_espresso' )
231
			)
232
		);
233
	}
234
235
236
237
	/**
238
	 * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle accordingly.
239
	 *
240
	 * @param array  $response The existing heartbeat response array.
241
	 * @param array  $data        The incoming data package.
242
	 *
243
	 * @return array  possibly appended response.
244
	 */
245
	public function heartbeat_response( $response, $data ) {
246
		/**
247
		 * check whether count of tickets is approaching the potential
248
		 * limits for the server.
249
		 */
250
		if ( ! empty( $data['input_count'] ) ) {
251
			$response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check($data['input_count']);
252
		}
253
254
		return $response;
255
	}
256
257
258
259
	protected function _add_screen_options_ticket_list_table() {
260
		$this->_per_page_screen_option();
261
	}
262
263
264
265
	public function extra_permalink_field_buttons( $return, $id, $new_title, $new_slug ) {
266
		$return = parent::extra_permalink_field_buttons( $return, $id, $new_title, $new_slug );
267
		//make sure this is only when editing
268
		if ( !empty( $id ) ) {
269
			$href = EE_Admin_Page::add_query_args_and_nonce( array('action' => 'duplicate_event', 'EVT_ID' => $id), $this->_admin_base_url );
270
			$title = esc_attr__('Duplicate Event', 'event_espresso');
271
			$return .= '<a href="' . $href . '" title="' . $title . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">' . $title  . '</button>';
272
		}
273
		return $return;
274
	}
275
276
277
278
279 View Code Duplication
	public function _set_list_table_views_ticket_list_table() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
		$this->_views = array(
281
			'all' => array(
282
				'slug' => 'all',
283
				'label' => __('All', 'event_espresso'),
284
				'count' => 0,
285
				'bulk_action' => array(
286
					'trash_tickets' => __('Move to Trash', 'event_espresso')
287
					)
288
				),
289
			'trashed' => array(
290
				'slug' => 'trashed',
291
				'label' => __('Trash', 'event_espresso'),
292
				'count' => 0,
293
				'bulk_action' => array(
294
					'restore_tickets' => __('Restore from Trash' , 'event_espresso'),
295
					'delete_tickets' => __('Delete Permanently', 'event_espresso')
296
					)
297
				)
298
			);
299
	}
300
301
302
303
	public function load_scripts_styles_edit() {
304
		wp_register_script( 'ee-event-editor-heartbeat', EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js', array( 'ee_admin_js', 'heartbeat' ), EVENT_ESPRESSO_VERSION, TRUE );
305
306
		/**
307
		 * load accounting js.
308
		 */
309
		add_filter('FHEE_load_accounting_js', '__return_true');
310
311
		//styles
312
		wp_enqueue_style('espresso-ui-theme');
313
		wp_enqueue_script('event_editor_js');
314
		wp_enqueue_script('ee-event-editor-heartbeat');
315
316
	}
317
318
319
320
321
322
323
	public function add_additional_datetime_button( $template, $template_args ) {
324
		return EEH_Template::display_template( EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php', $template_args, TRUE);
325
	}
326
327
328
329
	public function add_datetime_clone_button( $template, $template_args ) {
330
		return EEH_Template::display_template( EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php', $template_args, TRUE );
331
	}
332
333
334
335
	public function datetime_timezones_template( $template, $template_args ) {
336
		return EEH_Template::display_template( EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php', $template_args, TRUE );
337
	}
338
339
340
341
342
	protected function _set_list_table_views_default() {
343
		parent::_set_list_table_views_default();
344
		$export_label = __('Export Events', 'event_espresso');
0 ignored issues
show
Unused Code introduced by
$export_label is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
345
		if ( EE_Registry::instance()->CAP->current_user_can( 'export', 'espresso_events_export' ) ) {
346
//			$this->_views['all']['bulk_action']['export_events'] = $export_label;
347
//			$this->_views['draft']['bulk_action']['export_events'] = $export_label;
348
349
			if ( EE_Registry::instance()->CAP->current_user_can( 'ee_delete_events', 'espresso_events_trash_events' ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
350
//				$this->_views['trash']['bulk_action']['export_events'] = $export_label;
351
			}
352
		}
353
354
		$new_views = array(
355
			'today' => array(
356
				'slug' => 'today',
357
				'label' => __('Today', 'event_espresso'),
358
				'count' => $this->total_events_today(),
359
				'bulk_action' => array(
360
//					'export_events' => __('Export Events', 'event_espresso'),
361
					'trash_events' => __('Move to Trash', 'event_espresso')
362
				)
363
			),
364
			'month' => array(
365
				'slug' => 'month',
366
				'label' => __('This Month', 'event_espresso'),
367
				'count' => $this->total_events_this_month(),
368
				'bulk_action' => array(
369
//					'export_events' => __('Export Events', 'event_espresso'),
370
					'trash_events' => __('Move to Trash', 'event_espresso')
371
				)
372
			)
373
		);
374
375
		$this->_views = array_merge( $this->_views, $new_views);
376
	}
377
378
379
380
381
	protected function _set_list_table_views_category_list() {
382
		parent::_set_list_table_views_category_list();
383
//		$this->_views['all']['bulk_action']['export_categories'] = __('Export Categories', 'event_espresso');
384
	}
385
386
387
388
389 View Code Duplication
	public function extra_list_table_actions( $actionlinks, $event ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
390
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_read_registrations', 'espresso_registrations_reports', $event->ID() ) ) {
391
			$reports_query_args = array(
392
					'action' => 'reports',
393
					'EVT_ID' => $event->ID()
394
				);
395
			$reports_link = EE_Admin_Page::add_query_args_and_nonce( $reports_query_args, REG_ADMIN_URL );
396
			$actionlinks[] = '<a href="' . $reports_link . '" title="' .  esc_attr__('View Report', 'event_espresso') . '"><div class="dashicons dashicons-chart-bar"></div></a>' . "\n\t";
397
		}
398
		return $actionlinks;
399
	}
400
401
402
403
	public function additional_legend_items($items) {
404
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_read_registrations', 'espresso_registrations_reports' ) ) {
405
			$items['reports'] = array(
406
					'class' => 'dashicons dashicons-chart-bar',
407
					'desc' => __('Event Reports', 'event_espresso')
408
				);
409
		}
410
		$items['empty'] = array('class'=>'empty', 'desc' => '');
411
		return $items;
412
	}
413
414
415
416
	/**
417
	 * This is the callback method for the duplicate event route
418
	 *
419
	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
420
	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
421
	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
422
	 * After duplication the redirect is to the new event edit page.
423
	 * @return void
424
	 * @access protected
425
	 * @throws EE_Error If EE_Event is not available with given ID
426
	 */
427
	protected function _duplicate_event() {
428
		//first make sure the ID for the event is in the request.  If it isnt' then we need to bail and redirect back to overview list table (cause how did we get here?)
429
		if ( !isset( $this->_req_data['EVT_ID'] ) ) {
430
			EE_Error::add_error( __('In order to duplicate an event an Event ID is required.  None was given.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
431
			$this->_redirect_after_action( FALSE, '', '', array(), TRUE );
432
			return;
433
		}
434
435
		//k we've got EVT_ID so let's use that to get the event we'll duplicate
436
		$orig_event = EEM_Event::instance()->get_one_by_ID( $this->_req_data['EVT_ID'] );
437
438
		if ( ! $orig_event instanceof EE_Event )
439
			throw new EE_Error( sprintf( __('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso '), $this->_req_data['EVT_ID'] ) );
440
441
		//k now let's clone the $orig_event before getting relations
442
		$new_event = clone $orig_event;
443
444
		//original datetimes
445
		$orig_datetimes = $orig_event->get_many_related('Datetime');
446
447
		//other original relations
448
		$orig_ven = $orig_event->get_many_related('Venue');
449
450
451
		//reset the ID and modify other details to make it clear this is a dupe
452
		$new_event->set( 'EVT_ID', 0 );
453
		$new_name = $new_event->name() . ' ' . __('**DUPLICATE**', 'event_espresso');
454
		$new_event->set( 'EVT_name',  $new_name );
455
		$new_event->set( 'EVT_slug',  wp_unique_post_slug( sanitize_title( $orig_event->name() ), 0, 'publish', 'espresso_events', 0 ) );
456
		$new_event->set( 'status', 'draft' );
457
458
		//duplicate discussion settings
459
		$new_event->set( 'comment_status', $orig_event->get('comment_status') );
460
		$new_event->set( 'ping_status', $orig_event->get( 'ping_status' ) );
461
462
		//save the new event
463
		$new_event->save();
464
465
		//venues
466
		foreach( $orig_ven as $ven ) {
467
			$new_event->_add_relation_to( $ven, 'Venue' );
468
		}
469
		$new_event->save();
470
471
472
		//now we need to get the question group relations and handle that
473
		//first primary question groups
474
		$orig_primary_qgs = $orig_event->get_many_related('Question_Group', array( array('Event_Question_Group.EQG_primary' => 1 ) ) );
475 View Code Duplication
		if ( !empty( $orig_primary_qgs ) ) {
476
			foreach ( $orig_primary_qgs as $id => $obj ) {
477
				if ( $obj instanceof EE_Question_Group ) {
478
					$new_event->_add_relation_to( $obj, 'Question_Group', array( 'EQG_primary' => 1 ) );
479
				}
480
			}
481
		}
482
483
		//next additional attendee question groups
484
		$orig_additional_qgs = $orig_event->get_many_related('Question_Group', array( array('Event_Question_Group.EQG_primary' => 0 ) ) );
485 View Code Duplication
		if ( !empty( $orig_additional_qgs ) ) {
486
			foreach ( $orig_additional_qgs as $id => $obj ) {
487
				if ( $obj instanceof EE_Question_Group ) {
488
					$new_event->_add_relation_to( $obj, 'Question_Group', array( 'EQG_primary' => 0 ) );
489
				}
490
			}
491
		}
492
493
		//now save
494
		$new_event->save();
495
496
497
		//k now that we have the new event saved we can loop through the datetimes and start adding relations.
498
		$cloned_tickets = array();
499
		foreach ( $orig_datetimes as $orig_dtt ) {
500
			$new_dtt = clone $orig_dtt;
501
			$orig_tkts = $orig_dtt->tickets();
0 ignored issues
show
Documentation Bug introduced by
The method tickets does not exist on object<EE_Base_Class>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
502
503
			//save new dtt then add to event
504
			$new_dtt->set('DTT_ID', 0);
505
			$new_dtt->set('DTT_sold', 0);
506
			$new_dtt->save();
507
			$new_event->_add_relation_to( $new_dtt, 'Datetime');
508
			$new_event->save();
509
510
			//now let's get the ticket relations setup.
511
			foreach ( (array) $orig_tkts as $orig_tkt ) {
512
				//it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
513
				if ( ! $orig_tkt instanceof EE_Ticket )
514
					continue;
515
516
				//is this ticket archived?  If it is then let's skip
517
				if ( $orig_tkt->get( 'TKT_deleted' ) ) {
518
					continue;
519
				}
520
521
				//does this original ticket already exist in the clone_tickets cache?  If so we'll just use the new ticket from it.
522
				if ( isset( $cloned_tickets[$orig_tkt->ID()] ) ) {
523
					$new_tkt = $cloned_tickets[$orig_tkt->ID()];
524
				} else {
525
					$new_tkt = clone $orig_tkt;
526
					//get relations on the $orig_tkt that we need to setup.
527
					$orig_prices = $orig_tkt->prices();
528
					$new_tkt->set('TKT_ID', 0);
529
					$new_tkt->set('TKT_sold', 0);
530
531
					$new_tkt->save(); //make sure new ticket has ID.
532
533
					//price relations on new ticket need to be setup.
534
					foreach ( $orig_prices as $orig_price ) {
535
						$new_price = clone $orig_price;
536
						$new_price->set('PRC_ID', 0);
537
						$new_price->save();
538
						$new_tkt->_add_relation_to($new_price, 'Price');
539
						$new_tkt->save();
540
					}
541
				}
542
543
				//k now we can add the new ticket as a relation to the new datetime and make sure its added to our cached $cloned_tickets array for use with later datetimes that have the same ticket.
544
				$new_dtt->_add_relation_to($new_tkt, 'Ticket');
545
				$new_dtt->save();
546
				$cloned_tickets[$orig_tkt->ID()] = $new_tkt;
547
			}
548
		}
549
550
		//clone taxonomy information
551
		$taxonomies_to_clone_with = apply_filters( 'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone', array( 'espresso_event_categories', 'espresso_event_type', 'post_tag' ) );
552
553
		//get terms for original event (notice)
554
		$orig_terms = wp_get_object_terms( $orig_event->ID(), $taxonomies_to_clone_with );
555
556
		//loop through terms and add them to new event.
557
		foreach ( $orig_terms as $term ) {
558
			wp_set_object_terms( $new_event->ID(), $term->term_id, $term->taxonomy, true );
559
		}
560
561
562
		do_action( 'AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event );
563
564
		//now let's redirect to the edit page for this duplicated event if we have a new event id.
565
		if ( $new_event->ID() ) {
566
			$redirect_args = array(
567
				'post' => $new_event->ID(),
568
				'action' => 'edit'
569
			);
570
			EE_Error::add_success( __('Event successfully duplicated.  Please review the details below and make any necessary edits', 'event_espresso') );
571
		} else {
572
			$redirect_args = array(
573
				'action' => 'default'
574
				);
575
			EE_Error::add_error( __('Not able to duplicate event.  Something went wrong.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__ );
576
		}
577
578
		$this->_redirect_after_action(FALSE, '', '', $redirect_args, TRUE );
579
	}
580
581
582
583
	protected function _import_page(){
584
585
		$title = __('Import', 'event_espresso');
586
		$intro = __('If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ', 'event_espresso');
587
		$form_url = EVENTS_ADMIN_URL;
588
		$action = 'import_events';
589
		$type = 'csv';
590
		$this->_template_args['form'] = EE_Import::instance()->upload_form($title, $intro, $form_url, $action, $type);
591
		$this->_template_args['sample_file_link'] = EE_Admin_Page::add_query_args_and_nonce(array('action'=>'sample_export_file'),$this->_admin_base_url);
592
		$content = EEH_Template::display_template(EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',$this->_template_args,true);
593
594
595
		$this->_template_args['admin_page_content'] = $content;
596
		$this->display_admin_page_with_sidebar();
597
	}
598
	/**
599
	 * _import_events
600
	 * This handles displaying the screen and running imports for importing events.
601
	 *
602
	 * @return string html
603
	 */
604
	protected function _import_events() {
605
		require_once(EE_CLASSES . 'EE_Import.class.php');
606
		$success = EE_Import::instance()->import();
607
		$this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'),true);
0 ignored issues
show
Documentation introduced by
$success is of type boolean|null, but the function expects a false|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
608
609
	}
610
611
612
613
	/**
614
	 * _events_export
615
	 * Will export all (or just the given event) to a Excel compatible file.
616
	 *
617
	 * @access protected
618
	 * @return file
619
	 */
620
	protected function _events_export() {
621
		if(isset($this->_req_data['EVT_ID'])){
622
			$event_ids = $this->_req_data['EVT_ID'];
623
		}elseif(isset($this->_req_data['EVT_IDs'])){
624
			$event_ids = $this->_req_data['EVT_IDs'];
625
		}else{
626
			$event_ids = NULL;
627
		}
628
		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
629
		$new_request_args = array(
630
			'export' => 'report',
631
			'action' => 'all_event_data',
632
			'EVT_ID' => $event_ids ,
633
		);
634
		$this->_req_data = array_merge($this->_req_data, $new_request_args);
635
636
		EE_Registry::instance()->load_helper( 'File' );
637
		if ( is_readable(EE_CLASSES . 'EE_Export.class.php')) {
638
			require_once(EE_CLASSES . 'EE_Export.class.php');
639
			$EE_Export = EE_Export::instance($this->_req_data);
640
			$EE_Export->export();
641
		}
642
	}
643
644
645
646
647
	/**
648
	 * handle category exports()
649
	 * @return file export
650
	 */
651 View Code Duplication
	protected function _categories_export() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
652
653
		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
654
		$new_request_args = array(
655
			'export' => 'report',
656
			'action' => 'categories',
657
			'category_ids' => $this->_req_data['EVT_CAT_ID']
658
			);
659
660
		$this->_req_data = array_merge( $this->_req_data, $new_request_args );
661
662
		EE_Registry::instance()->load_helper( 'File' );
663
		if ( is_readable( EE_CLASSES . 'EE_Export.class.php') ) {
664
			require_once( EE_CLASSES . 'EE_Export.class.php');
665
			$EE_Export = EE_Export::instance( $this->_req_data );
666
			$EE_Export->export();
667
		}
668
669
	}
670
671
672
673
	/**
674
	 * Creates a sample CSV file for importing
675
	 */
676
	protected function _sample_export_file(){
677
//		require_once(EE_CLASSES . 'EE_Export.class.php');
678
		EE_Export::instance()->export_sample();
679
	}
680
681
682
683
	/*************		Template Settings 		*************/
684
685
686
687 View Code Duplication
	protected function _template_settings() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
688
		$this->_template_args['values'] = $this->_yes_no_values;
689
		/**
690
		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
691
		 * from General_Settings_Admin_Page to here.
692
		 */
693
		$this->_template_args = apply_filters( 'FHEE__General_Settings_Admin_Page__template_settings__template_args', $this->_template_args );
694
		$this->_set_add_edit_form_tags( 'update_template_settings' );
695
		$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
696
		$this->_template_args['admin_page_content'] = EEH_Template::display_template( EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php', $this->_template_args, TRUE );
697
		$this->display_admin_page_with_sidebar();
698
	}
699
700
701
702
	protected function _update_template_settings() {
703
704
		/**
705
		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
706
		 * from General_Settings_Admin_Page to here.
707
		 */
708
		EE_Registry::instance()->CFG->template_settings = apply_filters( 'FHEE__General_Settings_Admin_Page__update_template_settings__data', EE_Registry::instance()->CFG->template_settings, $this->_req_data );
709
710
711
		//update custom post type slugs and detect if we need to flush rewrite rules
712
		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
713
		EE_Registry::instance()->CFG->core->event_cpt_slug = empty( $this->_req_data['event_cpt_slug'] ) ? EE_Registry::instance()->CFG->core->event_cpt_slug : sanitize_title_with_dashes( $this->_req_data['event_cpt_slug'] );
714
715
716
		$what = 'Template Settings';
717
		$success = $this->_update_espresso_configuration( $what, EE_Registry::instance()->CFG->template_settings, __FILE__, __FUNCTION__, __LINE__ );
718
719
720
		if ( EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug ) {
721
			update_option( 'ee_flush_rewrite_rules', true );
722
		}
723
724
725
		$this->_redirect_after_action( $success, $what, 'updated', array( 'action' => 'template_settings' ) );
0 ignored issues
show
Documentation introduced by
$success is of type boolean, but the function expects a false|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
726
727
	}
728
729
730
731
732
	/**
733
	 * _premium_event_editor_meta_boxes
734
	 * add all metaboxes related to the event_editor
735
	 *
736
	 * @access protected
737
	 * @return void
738
	 */
739
	protected function _premium_event_editor_meta_boxes() {
740
741
		$this->verify_cpt_object();
742
743
		add_meta_box('espresso_event_editor_event_options', __('Event Registration Options', 'event_espresso'), array( $this, 'registration_options_meta_box' ), $this->page_slug, 'side', 'core');
744
		//add_meta_box('espresso_event_types', __('Event Type', 'event_espresso'), array( $this, 'event_type_meta_box' ), $this->page_slug, 'side', 'default' ); //add this back in when the feature is ready.
745
746
		//todo feature in progress
747
		//add_meta_box('espresso_event_editor_promo_box', __('Event Promotions', 'event_espresso'), array( $this, 'promotions_meta_box' ), $this->_current_screen->id, 'side', 'core');
748
749
		//todo, this will morph into the "Person" metabox once events are converted to cpts and we have the persons cpt in place.
750
		/*if ( EE_Registry::instance()->CFG->admin->use_personnel_manager ) {
751
			add_meta_box('espresso_event_editor_personnel_box', __('Event Staff / Speakers', 'event_espresso'), array( $this, 'personnel_metabox' ), $this->page_slug, 'side', 'default');
752
		}/**/
753
	}
754
755
756
757
	/**
758
	 * override caf metabox
759
	 * @return string html contents
760
	 */
761
	public function registration_options_meta_box() {
762
763
		$yes_no_values = array(
764
			array('id' => true, 'text' => __('Yes', 'event_espresso')),
765
			array('id' => false, 'text' => __('No', 'event_espresso'))
766
		);
767
		$default_reg_status_values = EEM_Registration::reg_status_array(array(EEM_Registration::status_id_cancelled, EEM_Registration::status_id_declined, EEM_Registration::status_id_incomplete ), TRUE);
768
		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(FALSE);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$template_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $template_args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
Bug introduced by
The method pretty_active_status() does not exist on EE_CPT_Base. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
769
		$template_args['_event'] = $this->_cpt_model_obj;
770
		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
0 ignored issues
show
Documentation Bug introduced by
The method additional_limit does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
771
		$template_args['default_registration_status'] = EEH_Form_Fields::select_input('default_reg_status', $default_reg_status_values, $this->_cpt_model_obj->default_registration_status());
0 ignored issues
show
Bug introduced by
The method default_registration_status() does not exist on EE_CPT_Base. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
772
		$template_args['display_description'] = EEH_Form_Fields::select_input('display_desc', $yes_no_values, $this->_cpt_model_obj->display_description());
0 ignored issues
show
Documentation Bug introduced by
The method display_description does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
773
		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input('display_ticket_selector', $yes_no_values, $this->_cpt_model_obj->display_ticket_selector(), '', '', false);
0 ignored issues
show
Documentation Bug introduced by
The method display_ticket_selector does not exist on object<EE_CPT_Base>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
774
		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input('EVT_default_registration_status', $default_reg_status_values, $this->_cpt_model_obj->default_registration_status() );
0 ignored issues
show
Bug introduced by
The method default_registration_status() does not exist on EE_CPT_Base. Did you maybe mean status()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
775
		$template_args['additional_registration_options'] = apply_filters( 'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options', '', $template_args, $yes_no_values, $default_reg_status_values );
776
		$templatepath = EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php';
777
		EEH_Template::display_template($templatepath, $template_args);
778
	}
779
780
781
782
783
	/**
784
	 * event type metabox for events
785
	 * @param  object $post current post object
786
	 * @param  array  $box  metabox args
787
	 * @return string       metabox contents
788
	 */
789
	public function event_type_meta_box( $post, $box ) {
0 ignored issues
show
Unused Code introduced by
The parameter $box is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
790
		$template_args['radio_list'] = $this->wp_terms_radio($post->ID, array( 'taxonomy' => 'espresso_event_type' ) );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$template_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $template_args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
791
		$template = EVENTS_CAF_TEMPLATE_PATH . 'event_type_metabox_contents.template.php';
792
		EEH_Template::display_template($template, $template_args);
793
	}
794
795
796
797
798
799
800
801
	public function wp_terms_radio( $post_id = 0, $args = array() ) {
802
		$defaults = array(
803
			'descendants_and_self' => 0,
804
			'selected_cats' => false,
805
			'popular_cats' => false,
806
			'walker' => null,
807
			'taxonomy' => 'category',
808
			'checked_ontop' => true
809
		);
810
		$args = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
811
812
		extract( wp_parse_args($args, $defaults), EXTR_SKIP );
813
814
		if ( empty($walker) || !is_a($walker, 'Walker') )
815
			$walker = new Walker_Radio_Checklist;
816
817
		$descendants_and_self = (int) $descendants_and_self;
818
819
		$args = array('taxonomy' => $taxonomy);
820
821
		$tax = get_taxonomy($taxonomy);
822
		$args['disabled'] = !current_user_can($tax->cap->assign_terms);
823
824
		if ( is_array( $selected_cats ) )
825
			$args['selected_cats'] = $selected_cats;
826
		elseif ( $post_id )
827
			$args['selected_cats'] = wp_get_object_terms($post_id, $taxonomy, array_merge($args, array('fields' => 'ids')));
828
		else
829
			$args['selected_cats'] = array();
830
831
		if ( is_array( $popular_cats ) )
832
			$args['popular_cats'] = $popular_cats;
833
		else
834
			$args['popular_cats'] = get_terms( $taxonomy, array( 'fields' => 'ids', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
835
836
		if ( $descendants_and_self ) {
837
			$categories = (array) get_terms($taxonomy, array( 'child_of' => $descendants_and_self, 'hierarchical' => 0, 'hide_empty' => 0 ) );
838
			$self = get_term( $descendants_and_self, $taxonomy );
839
			array_unshift( $categories, $self );
840
		} else {
841
			$categories = (array) get_terms($taxonomy, array('get' => 'all'));
842
		}
843
844
		if ( $checked_ontop ) {
845
			// Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
846
			$checked_categories = array();
847
			$keys = array_keys( $categories );
848
849
			foreach( $keys as $k ) {
850
				if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
851
					$checked_categories[] = $categories[$k];
852
					unset( $categories[$k] );
853
				}
854
			}
855
856
			// Put checked cats on top
857
			$list = call_user_func_array(array(&$walker, 'walk'), array($checked_categories, 0, $args));
858
		}
859
		// Then the rest of them
860
		$list .= call_user_func_array(array(&$walker, 'walk'), array($categories, 0, $args));
861
		return $list;
862
	}
863
864
865
	/**
866
	 * wp_list_table_mods for caf
867
	 * ============================
868
	 */
869
870
871
	/**
872
	 * hook into list table filters and provide filters for caffeinated list table
873
	 * @param  array  $oldfilters     any existing filters present
874
	 * @param  array  $list_table_obj the list table object
875
	 * @return array                  new filters
876
	 */
877
	public function list_table_filters( $oldfilters, $list_table_obj ) {
0 ignored issues
show
Unused Code introduced by
The parameter $list_table_obj is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
878
		$filters = array();
879
880
		//first month/year filters
881
		$filters[] = $this->espresso_event_months_dropdown();
882
883
884
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
885
886
		//active status dropdown
887
		if ( $status !== 'draft' )
888
			$filter[] = $this->active_status_dropdown( isset( $this->_req_data['active_status'] ) ? $this->_req_data['active_status'] : '' );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$filter was never initialized. Although not strictly required by PHP, it is generally a good practice to add $filter = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
889
890
		//category filter
891
		$filters[] = $this->category_dropdown();
892
893
894
		return array_merge($oldfilters, $filters);
895
	}
896
897
898
899
900
901
902
	/**
903
	 * espresso_event_months_dropdown
904
	 *
905
	 * @access public
906
	 * @return string                dropdown listing month/year selections for events.
907
	 */
908
	public function espresso_event_months_dropdown() {
909
		//what we need to do is get all PRIMARY datetimes for all events to filter on. Note we need to include any other filters that are set!
910
		$status = isset( $this->_req_data['status'] ) ? $this->_req_data['status'] : NULL;
911
912
		//categories?
913
		$category = isset( $this->_req_data['EVT_CAT'] ) && $this->_req_data['EVT_CAT'] > 0 ? $this->_req_data['EVT_CAT'] : NULL;
914
915
		//active status?
916
		$active_status = isset( $this->_req_data['active_status'] ) ? $this->_req_data['active_status'] : NULL;
917
918
		$cur_date = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
919
920
		return EEH_Form_Fields::generate_event_months_dropdown( $cur_date, $status, $category, $active_status );
921
	}
922
923
924
925
926
	/**
927
	 * returns a list of "active" statuses on the event
928
	 * @param  string $current_value whatever the ucrrent active status is
929
	 * @return string                html dropdown.
930
	 */
931
	public function  active_status_dropdown( $current_value = '' ) {
932
		$select_name = 'active_status';
933
		$values = array('none' => __('Show Active/Inactive', 'event_espresso'), 'active' => __('Active', 'event_espresso'), 'upcoming' => __('Upcoming', 'event_espresso'), 'expired' => __('Expired', 'event_espresso'), 'inactive' => __('Inactive', 'event_espresso') );
934
		$id = 'id="espresso-active-status-dropdown-filter"';
935
		$class = 'wide';
936
		echo EEH_Form_Fields::select_input( $select_name, $values, $current_value, $id, $class );
937
	}
938
939
940
941
	/**
942
	 * output a dropdown of the categories for the category filter on the event admin list table
943
	 *
944
	 * @access  public
945
	 * @return string html
946
	 */
947
	public function category_dropdown() {
948
		$cur_cat = isset( $this->_req_data['EVT_CAT'] ) ? $this->_req_data['EVT_CAT'] : -1;
949
950
		return EEH_Form_Fields::generate_event_category_dropdown( $cur_cat );
951
	}
952
953
954
955
	/**
956
	 * get total number of events today
957
	 *
958
	 * @access public
959
	 * @return int
960
	 */
961
	public function total_events_today() {
962
		$start = EEM_Datetime::instance()->convert_datetime_for_query( 'DTT_EVT_start', date('Y-m-d' ) . ' 00:00:00', 'Y-m-d H:i:s', 'UTC' );
963
		$end = EEM_Datetime::instance()->convert_datetime_for_query( 'DTT_EVT_start', date('Y-m-d' ) . ' 23:59:59', 'Y-m-d H:i:s', 'UTC' );
964
965
		$where = array(
966
			'Datetime.DTT_EVT_start' => array( 'BETWEEN', array($start, $end ) )
967
			);
968
969
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
970
		return $count;
971
	}
972
973
	/**
974
	 * get total number of events this month
975
	 *
976
	 * @access public
977
	 * @return int
978
	 */
979
	public function total_events_this_month() {
980
		//Dates
981
		$this_year_r = date('Y');
982
		$this_month_r = date('m');
983
		$days_this_month = date('t');
984
		$start = EEM_Datetime::instance()->convert_datetime_for_query( 'DTT_EVT_start', $this_year_r . '-' . $this_month_r . '-01 00:00:00', 'Y-m-d H:i:s', 'UTC' );
985
		$end = EEM_Datetime::instance()->convert_datetime_for_query( 'DTT_EVT_start', $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59', 'Y-m-d H:i:s', 'UTC' );
986
987
		$where = array(
988
			'Datetime.DTT_EVT_start' => array( 'BETWEEN', array($start, $end ) )
989
			);
990
991
		$count = EEM_Event::instance()->count( array( $where, 'caps' => 'read_admin' ), 'EVT_ID', true );
992
		return $count;
993
	}
994
995
996
997
998
	/** DEFAULT TICKETS STUFF **/
999
1000
	public function _tickets_overview_list_table() {
1001
		$this->_search_btn_label = __('Tickets', 'event_espresso');
1002
		$this->display_admin_list_table_page_with_no_sidebar();
1003
	}
1004
1005
1006
1007
1008 View Code Duplication
	public function get_default_tickets( $per_page = 10, $count = FALSE, $trashed = FALSE ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1009
1010
		$orderby= empty( $this->_req_data['orderby'] ) ? 'TKT_name' : $this->_req_data['orderby'];
1011
		$order = empty( $this->_req_data['order'] ) ? 'ASC' : $this->_req_data['order'];
1012
1013
		switch ( $orderby ) {
1014
			case 'TKT_name' :
1015
				$orderby = array( 'TKT_name' => $order );
1016
				break;
1017
1018
			case 'TKT_price' :
1019
				$orderby = array( 'TKT_price' => $order );
1020
				break;
1021
1022
			case 'TKT_uses' :
1023
				$orderby = array( 'TKT_uses' => $order );
1024
				break;
1025
1026
			case 'TKT_min' :
1027
				$orderby = array( 'TKT_min' => $order );
1028
				break;
1029
1030
			case 'TKT_max' :
1031
				$orderby = array( 'TKT_max' => $order );
1032
				break;
1033
1034
			case 'TKT_qty' :
1035
				$orderby = array( 'TKT_qty' => $order );
1036
				break;
1037
		}
1038
1039
		$current_page = isset( $this->_req_data['paged'] ) && !empty( $this->_req_data['paged'] ) ? $this->_req_data['paged'] : 1;
1040
		$per_page = isset( $this->_req_data['perpage'] ) && !empty( $this->_req_data['perpage'] ) ? $this->_req_data['perpage'] : $per_page;
1041
1042
		$_where = array(
1043
			'TKT_is_default' => 1,
1044
			'TKT_deleted' => $trashed
1045
			);
1046
1047
		$offset = ($current_page-1)*$per_page;
1048
		$limit = array( $offset, $per_page );
1049
1050
		if ( isset( $this->_req_data['s'] ) ) {
1051
			$sstr = '%' . $this->_req_data['s'] . '%';
1052
			$_where['OR'] = array(
1053
				'TKT_name' => array('LIKE',$sstr ),
1054
				'TKT_description' => array('LIKE',$sstr )
1055
				);
1056
		}
1057
1058
		$query_params = array(
1059
			$_where,
1060
			'order_by'=>$orderby,
1061
			'limit'=>$limit,
1062
			'group_by'=>'TKT_ID'
1063
			);
1064
1065
		if($count){
1066
			return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1067
		}else{
1068
			return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1069
		}
1070
1071
	}
1072
1073
1074
1075
1076
1077
	protected function _trash_or_restore_ticket(  $trash = FALSE ) {
1078
		$success = 1;
1079
1080
		$TKT = EEM_Ticket::instance();
1081
1082
		//checkboxes?
1083 View Code Duplication
		if ( !empty( $this->_req_data['checkbox'] ) && is_array( $this->_req_data['checkbox'] ) ) {
1084
			//if array has more than one element then success message should be plural
1085
			$success = count( $this->_req_data['checkbox'] ) > 1 ? 2 : 1;
1086
1087
			//cycle thru the boxes
1088
			while ( list( $TKT_ID, $value ) = each( $this->_req_data['checkbox'] ) ) {
0 ignored issues
show
Unused Code introduced by
The assignment to $value is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1089
				if ( $trash ) {
1090
					if ( ! $TKT->delete_by_ID( $TKT_ID ) )
1091
						$success = 0;
1092
				} else {
1093
					if ( ! $TKT->restore_by_ID( $TKT_ID ) )
1094
						$success = 0;
1095
				}
1096
			}
1097
		} else {
1098
			//grab single id and trash
1099
			$TKT_ID = absint( $this->_req_data['TKT_ID'] );
1100
1101
			if ( $trash ) {
1102
				if ( ! $TKT->delete_by_ID( $TKT_ID ) )
1103
					$success = 0;
1104
			} else {
1105
				if ( ! $TKT->restore_by_ID( $TKT_ID ) )
1106
					$success = 0;
1107
			}
1108
		}
1109
1110
		$action_desc = $trash ? 'moved to the trash' : 'restored';
1111
		$query_args = array(
1112
			'action' => 'ticket_list_table',
1113
			'status' => $trash ? '' : 'trashed'
1114
			);
1115
		$this->_redirect_after_action( $success, 'Tickets', $action_desc, $query_args );
1116
	}
1117
1118
1119
1120
1121
1122
	protected function _delete_ticket() {
1123
		$success = 1;
1124
1125
		$TKT = EEM_Ticket::instance();
0 ignored issues
show
Unused Code introduced by
$TKT is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1126
1127
		//checkboxes?
1128 View Code Duplication
		if ( !empty( $this->_req_data['checkbox'] ) && is_array( $this->_req_data['checkbox'] ) ) {
1129
			//if array has more than one element then success message should be plural
1130
			$success = count( $this->_req_data['checkbox'] ) > 1 ? 2 : 1;
1131
1132
			//cycle thru the boxes
1133
			while ( list( $TKT_ID, $value ) = each( $this->_req_data['checkbox'] ) ) {
0 ignored issues
show
Unused Code introduced by
The assignment to $value is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1134
				//delete
1135
				if ( ! $this->_delete_the_ticket( $TKT_ID ) ) {
1136
					$success = 0;
1137
				}
1138
			}
1139
		} else {
1140
			//grab single id and trash
1141
			$TKT_ID = absint( $this->_req_data['TKT_ID'] );
1142
			if ( ! $this->_delete_the_ticket( $TKT_ID ) ) {
1143
					$success = 0;
1144
				}
1145
		}
1146
1147
		$action_desc = 'deleted';
1148
		$query_args = array(
1149
			'action' => 'ticket_list_table',
1150
			'status' => 'trashed'
1151
			);
1152
1153
		//failsafe.  If the default ticket count === 1 then we need to redirect to event overview.
1154
		if ( EEM_Ticket::instance()->count_deleted_and_undeleted( array( array( 'TKT_is_default' => 1 ) ), 'TKT_ID', TRUE ) )
1155
			$query_args = array();
1156
		$this->_redirect_after_action( $success, 'Tickets', $action_desc, $query_args );
1157
	}
1158
1159
1160
1161
1162
	protected function _delete_the_ticket( $TKT_ID ) {
1163
		$tkt = EEM_Ticket::instance()->get_one_by_ID( $TKT_ID );
1164
		$tkt->_remove_relations('Datetime');
1165
		//delete all related prices first
1166
		$tkt->delete_related_permanently('Price');
1167
		return $tkt->delete_permanently();
1168
	}
1169
1170
1171
1172
} //end class Events_Admin_Page
1173
1174
/*
1175
// Walker_Radio_Checklist isn't used anywhere in EE4 core currently, commenting out for now
1176
// The version check was added to make sure Walker_Category_Checklist class is available
1177
global $wp_version;
1178
if ( $wp_version >= 4.4 ){
1179
	require_once ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php'; 
1180
} else {
1181
	require_once ABSPATH . 'wp-admin/includes/template.php';
1182
}
1183
1184
class Walker_Radio_Checklist extends Walker_Category_Checklist {
1185
1186
	function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
1187
		extract($args);
1188
		if ( empty($taxonomy) )
1189
			$taxonomy = 'category';
1190
1191
		if ( $taxonomy == 'category' )
1192
			$name = 'post_category';
1193
		else
1194
			$name = 'tax_input['.$taxonomy.']';
1195
1196
		$class = '';
1197
		$output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" . '<label class="selectit"><input value="' . $category->term_id . '" type="radio" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->term_id . '"' . checked( in_array( $category->term_id, $selected_cats ), true, false ) . disabled( empty( $args['disabled'] ), false, false ) . ' /> ' . esc_html( apply_filters('the_category', $category->name )) . '</label>';
1198
	}
1199
}
1200
*/
1201