PluginProbe
Event Post / 5.5
Event Post v5.5
6.1.1 6.1.0 6.0.1 6.0.0 5.12.0 trunk 3.9 4.0 4.2 4.3 4.4 4.5 5.0 5.1 5.10.0 5.10.1 5.10.2 5.10.3 5.10.4 5.11.0 5.11.1 5.2 5.5 5.6 5.6.1 All 46 releases
event-post / eventpost.php

eventpost.php in Event Post 5.5, at eventpost.php

2,323 lines 77.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Event Post
4 Plugin URI: https://event-post.com?mtm_campaign=wp-plugin&mtm_kwd=event-post&mtm_medium=dashboard
5 Description: Add calendar and/or geolocation metadata on any posts.
6 Version: 5.5
7 Author: N.O.U.S. Open Useful and Simple
8 Contributors: bastho, sabrinaleroy, unecologeek, agencenous
9 Author URI: https://apps.avecnous.eu/?mtm_campaign=wp-plugin&mtm_kwd=event-post&mtm_medium=dashboard
10 License: GPLv2
11 Text Domain: event-post
12 Domain Path: /languages/
13 Tags: Post,posts,event,date,geolocalization,gps,widget,map,openstreetmap,EELV,calendar,agenda,blocks
14 */
15
16 /**
17 *
18 * @package event-post
19 */
20 global $EventPost;
21 $EventPost = new EventPost();
22
23 $EventPost_cache=array();
24
25 function EventPost(){
26 global $EventPost;
27 return $EventPost;
28 }
29
30 /**
31 * The main class where everything begins.
32 *
33 * Add calendar and/or geolocation metadata on posts
34 */
35 class EventPost {
36 const META_START = 'event_begin';
37 const META_END = 'event_end';
38 const META_COLOR = 'event_color';
39 // http://codex.wordpress.org/Geodata
40 const META_ADD = 'geo_address';
41 const META_LAT = 'geo_latitude';
42 const META_LONG = 'geo_longitude';
43 // https://schema.org/eventStatus
44 const META_STATUS = 'event_status';
45 // https://schema.org/location
46 const META_VIRTUAL_LOCATION = 'event_virtual_location';
47 // https://pending.schema.org/eventAttendanceMode
48 const META_ATTENDANCE_MODE = 'event_attendance_mode';
49
50 public $list_id;
51 public $NomDuMois;
52 public $Week;
53 public $settings;
54 public $dateformat;
55
56 private $pagination;
57 public $version = '5.3';
58 public $plugin_path ;
59 private $script_sufix;
60
61 public $map_interactions;
62 public $quick_edit_fields;
63
64 public $Shortcodes;
65
66 public $attendance_modes;
67 public $statuses;
68 private $is_schema_output=false;
69
70 public function __construct() {
71 add_action('init', array(&$this,'init'), 1);
72 add_action('widgets_init', array(&$this,'widgets_init'), 1);
73 add_action('save_post', array(&$this, 'save_postdata'));
74 add_filter('dashboard_glance_items', array(&$this, 'dashboard_right_now'));
75
76 // Scripts
77 add_action( 'admin_init', array(&$this, 'editor_styles'));
78 add_action('admin_enqueue_scripts', array(&$this, 'admin_head'));
79 add_action('admin_print_scripts', array(&$this, 'admin_scripts'));
80 add_action('wp_enqueue_scripts', array(&$this, 'load_styles'));
81
82 // Single
83 add_filter('the_content', array(&$this, 'display_single'), 9999);
84 add_filter('the_title', array(&$this, 'the_title'), 9999, 2);
85 add_action('the_event', array(&$this, 'print_single'));
86 add_action('wp_head', array(&$this, 'single_header'));
87 add_action('wpseo_schema_webpage', array(&$this, 'wpseo_schema_webpage'));
88
89 // Ajax
90 add_action('wp_ajax_EventPostGetLatLong', array(&$this, 'GetLatLong'));
91 add_action('wp_ajax_EventPostHumanDate', array(&$this, 'HumanDate'));
92 add_action('wp_ajax_EventPostList', array(&$this, 'ajaxlist'));
93 add_action('wp_ajax_EventPostMap', array(&$this, 'ajaxmap'));
94 add_action('wp_ajax_EventPostCalendar', array(&$this, 'ajaxcal'));
95 add_action('wp_ajax_nopriv_EventPostCalendar', array(&$this, 'ajaxcal'));
96 add_action('wp_ajax_EventPostCalendarDate', array(&$this, 'ajaxdate'));
97 add_action('wp_ajax_nopriv_EventPostCalendarDate', array(&$this, 'ajaxdate'));
98
99 // Calendar publishing
100 add_action('parse_request', array(&$this, 'parse_request'), 100);
101 add_action('wp_ajax_EventPostExport', array(&$this, 'export'));
102 add_action('wp_ajax_nopriv_EventPostExport', array(&$this, 'export'));
103 add_action('wp_ajax_EventPostFeed', array(&$this, 'feed'));
104 add_action('wp_ajax_nopriv_EventPostFeed', array(&$this, 'feed'));
105
106 //
107 add_filter('eventpost_list_shema',array(&$this, 'custom_shema'),10,1);
108
109
110 add_action('widgets_init', array(&$this, 'register_widgets'),1,1);
111
112 // Quick edit
113 add_action( 'bulk_edit_custom_box', array( &$this, 'bulk_edit' ), 10, 2 );
114 add_action( 'quick_edit_custom_box', array( &$this, 'quick_edit' ), 10, 2 );
115 add_action( 'admin_print_scripts-edit.php', array(&$this, 'scripts_edit') );
116 add_action( 'wp_ajax_inline-save', array(&$this, 'inline_save'), 1 );
117 add_action( 'wp_ajax_eventpost_save_bulk', array(&$this, 'save_bulkdatas') );
118 add_filter( 'eventpost_inline_field', array(&$this, 'inline_field_color'), 10, 3);
119
120 $inc_path = plugin_dir_path(__FILE__).'inc/';
121 $this->plugin_path = plugin_dir_path(__FILE__);
122 include_once ($inc_path . 'settings.php');
123 include_once ($inc_path . 'wrappers.php');
124 include_once ($inc_path . 'widget.php');
125 include_once ($inc_path . 'widget.cal.php');
126 include_once ($inc_path . 'widget.map.php');
127 include_once ($inc_path . 'multisite.php');
128 include_once ($inc_path . 'shortcodes.php');
129 include_once ($inc_path . 'openweathermap.php');
130 include_once ($inc_path . 'children.php');
131
132 $this->Settings = new EventPost\Settings;
133 }
134
135 /**
136 * PHP4 constructor
137 */
138 public function EventPost(){
139 $this->__construct();
140 }
141
142 public function init(){
143 add_rewrite_rule('event-feed/?', admin_url('admin-ajax.php?action=EventPostFeed'), 'top');
144 add_rewrite_rule('eventpost/([0-9]*)\.(ics|vcs)?', plugins_url('export/ics.php', __FILE__), 'top');
145 }
146
147 /**
148 * Init all variables when WP is ready
149 *
150 * @action evenpost_init
151 * @filter eventpost_default_list_shema
152 * @filter eventpost_list_shema
153 */
154 public function widgets_init(){
155 $this->META_START = 'event_begin';
156 $this->META_END = 'event_end';
157 $this->META_COLOR = 'event_color';
158 // http://codex.wordpress.org/Geodata
159 $this->META_ADD = 'geo_address';
160 $this->META_LAT = 'geo_latitude';
161 $this->META_LONG = 'geo_longitude';
162 // https://schema.org/eventStatus
163 $this->META_STATUS = 'event_status';
164 // https://schema.org/location
165 $this->META_VIRTUAL_LOCATION = 'event_virtual_location';
166 // https://pending.schema.org/eventAttendanceMode
167 $this->META_ATTENDANCE_MODE = 'event_attendance_mode';
168 $this->list_id = 0;
169 $this->NomDuMois = array('', __('Jan', 'event-post'), __('Feb', 'event-post'), __('Mar', 'event-post'), __('Apr', 'event-post'), __('May', 'event-post'), __('Jun', 'event-post'), __('Jul', 'event-post'), __('Aug', 'event-post'), __('Sept', 'event-post'), __('Oct', 'event-post'), __('Nov', 'event-post'), __('Dec', 'event-post'));
170 $this->Week = array(__('Sunday', 'event-post'), __('Monday', 'event-post'), __('Tuesday', 'event-post'), __('Wednesday', 'event-post'), __('Thursday', 'event-post'), __('Friday', 'event-post'), __('Saturday', 'event-post'));
171 $this->attendance_modes = array(
172 'OfflineEventAttendanceMode' => _x('Physical', 'Attendance Mode', 'event-post'),
173 'MixedEventAttendanceMode' => _x('Mixed', 'Attendance Mode', 'event-post'),
174 'OnlineEventAttendanceMode' => _x('Online', 'Attendance Mode', 'event-post'),
175 );
176 $this->statuses = array(
177 'EventScheduled' =>_x('Scheduled', 'Event Status', 'event-post'),
178 'EventCancelled'=>_x('Cancelled', 'Event Status', 'event-post'),
179 'EventMovedOnline'=>_x('Moved Online', 'Event Status', 'event-post'),
180 'EventPostponed'=>_x('Postoned', 'Event Status', 'event-post'),
181 'EventRescheduled'=>_x('Rescheduled', 'Event Status', 'event-post'),
182 );
183
184 $this->maps = $this->get_maps();
185 $this->settings = $this->get_settings();
186
187 do_action('evenpost_init', $this);
188
189 $this->Shortcodes = new EventPost_Shortcodes();
190
191 if(function_exists('register_block_type')){
192 $block_path = plugin_dir_path(__FILE__).'inc/blocks/';
193 include_once ($block_path . 'eventslist.php');
194 include_once ($block_path . 'eventsmap.php');
195 include_once ($block_path . 'eventscalendar.php');
196 }
197
198 // Edit
199 add_action('add_meta_boxes', array(&$this, 'add_custom_box'));
200 foreach($this->settings['posttypes'] as $posttype){
201 add_filter('manage_'.$posttype.'_posts_columns', array(&$this, 'columns_head'), 2);
202 add_action('manage_'.$posttype.'_posts_custom_column', array(&$this, 'columns_content'), 10, 2);
203 }
204
205
206 if (!empty($this->settings['markpath']) && !empty($this->settings['markurl'])) {
207 $this->markpath = ABSPATH.'/'.$this->settings['markpath'];
208 $this->markurl = $this->settings['markurl'];
209 } else {
210 $this->markpath = plugin_dir_path(__FILE__) . 'markers/';
211 $this->markurl = plugins_url('/markers/', __FILE__);
212 }
213
214 $this->dateformat = str_replace(array('yy', 'mm', 'dd'), array('Y', 'm', 'd'), __('yy-mm-dd', 'event-post'));
215
216 $this->default_list_shema = apply_filters('eventpost_default_list_shema', array(
217 'container' => '
218 <%type% class="event_loop %id% %class%" id="%listid%" style="%style%" %attributes%>
219 %list%
220 %pagination%
221 </%type%><!-- .event_loop -->',
222 'item' => '
223 <%child% class="event_item %class%" data-color="%color%">
224 <a href="%event_link%">
225 %event_thumbnail%
226 <h5>%event_title%</h5>
227 </a>
228 %event_date%
229 %event_cat%
230 %event_location%
231 %event_excerpt%
232 </%child%><!-- .event_item -->'
233 ));
234 $this->list_shema = apply_filters('eventpost_list_shema',$this->default_list_shema);
235
236 $this->map_interactions=array(
237 'DragRotate'=>__('Drag Rotate', 'event-post'),
238 'DoubleClickZoom'=>__('Double Click Zoom', 'event-post'),
239 'DragPan'=>__('Drag Pan', 'event-post'),
240 'PinchRotate'=>__('Pinch Rotate', 'event-post'),
241 'PinchZoom'=>__('Pinch Zoom', 'event-post'),
242 'KeyboardPan'=>__('Keyboard Pan', 'event-post'),
243 'KeyboardZoom'=>__('Keyboard Zoom', 'event-post'),
244 'MouseWheelZoom'=>__('Mouse Wheel Zoom', 'event-post'),
245 'DragZoom'=>__('Drag Zoom', 'event-post'),
246 );
247
248 $this->quick_edit_fields = apply_filters('eventpost_quick_edit_fields', array(
249 'event'=>array(
250 $this->META_START=>__('Begin:', 'event-post'),
251 $this->META_END=>__('End:', 'event-post'),
252 $this->META_COLOR=>__('Color:', 'event-post'),
253 ),
254 'location'=>array(
255 $this->META_ADD=>__('Address:', 'event-post'),
256 $this->META_LAT=>__('Latitude:', 'event-post'),
257 $this->META_LONG=>__('Longitude:', 'event-post'),
258 ),
259 )
260 );
261 $this->bulk_edit_fields = apply_filters('eventpost_bulk_edit_fields', array(
262 'event'=>array(
263 $this->META_COLOR=>__('Color:', 'event-post'),
264 ),
265 )
266 );
267
268 }
269
270 public function register_widgets(){
271 register_widget('EventPost_List');
272 register_widget('EventPost_Map');
273 register_widget('EventPost_Cal');
274 }
275
276 /**
277 * Usefull hexadecimal to decimal converter. Returns an array of RGB from a given hexadecimal color.
278 * @param string $color
279 * @return array $color($R, $G, $B)
280 */
281 public function hex2dec($color = '000000') {
282 $tbl_color = array();
283 if (!strstr('#', $color)){
284 $color = '#' . $color;
285 }
286 $tbl_color['R'] = hexdec(substr($color, 1, 2));
287 $tbl_color['G'] = hexdec(substr($color, 3, 2));
288 $tbl_color['B'] = hexdec(substr($color, 5, 2));
289 return $tbl_color;
290 }
291 /**
292 * Fetch all registered image sizes
293 * @global array $_wp_additional_image_sizes
294 * @return array
295 */
296 function get_thumbnail_sizes(){
297 global $_wp_additional_image_sizes;
298 $sizes = array('thumbnail', 'medium', 'large', 'full');
299 foreach(array_keys($_wp_additional_image_sizes) as $size){
300 $sizes[]=$size;
301 }
302 return $sizes;
303 }
304
305 /**
306 * Get blog settings, load and saves default settings if needed. Can be filterred using
307 *
308 * `<?php add_filter('eventpost_getsettings', 'some_function'); ?>`
309 *
310 * @action eventpost_getsettings_action
311 * @filter eventpost_getsettings
312 * @return array
313 */
314 public function get_settings() {
315 $ep_settings = $this->Settings->get_settings();
316 return apply_filters('eventpost_getsettings', $ep_settings);
317 }
318
319 /**
320 * Checks if HTML schemas are not empty
321 * @param array $shema
322 * @return array
323 */
324 public function custom_shema($shema){
325 if(!empty($this->settings['container_shema'])){
326 $shema['container']=$this->settings['container_shema'];
327 }
328 if(!empty($this->settings['item_shema'])){
329 $shema['item']=$this->settings['item_shema'];
330 }
331 return $shema;
332 }
333
334 /**
335 * Parse the maps.json file. Custom maps can be added by using the `eventpost_getsettings` filter like the following example:
336 *
337 * ```
338 * <?php
339 * add_filter('eventpost_getsettings', 'map_function');
340 * function map_function($maps){
341 * array_push($maps, array(
342 * 'name'=>'Myt custom map',
343 * 'id'=>'custom_map',
344 * 'urls'=>array(
345 * 'http://a.customurl.org/{z}/{x}/{y}.png',
346 * 'http://b.customurl.org/{z}/{x}/{y}.png',
347 * 'http://c.customurl.org/{z}/{x}/{y}.png',
348 * )
349 * ));
350 * return $maps;
351 * }
352 * ?>
353 * ```
354 *
355 * @filter eventpost_maps
356 * @return array of map arrays ['name', 'id', 'urls']
357 */
358 public function get_maps() {
359 $maps = array();
360 $filename = plugin_dir_path(__FILE__) . 'maps.json';
361 if (is_file($filename) && (false !== $json = json_decode(file_get_contents($filename)))) {
362 // Convert objects to array to ensure retrocompatibility
363 $arrays = array();
364 foreach($json as $map){
365 $arrays[$map->id] = (array) $map;
366 }
367 $maps = apply_filters('eventpost_maps', $arrays);
368 }
369 return $maps;
370 }
371
372 /**
373 *
374 * @return array
375 */
376 public function get_colors() {
377 $colors = array();
378 if (is_dir($this->markpath)) {
379 $files = scandir($this->markpath);
380 foreach ($files as $file) {
381 if (substr($file, -4) == '.png') {
382 $colors[substr($file, 0, -4)] = $this->markurl . $file;
383 }
384 }
385 }
386 return $colors;
387 }
388
389 /**
390 *
391 * @param string $color
392 * @return sring
393 */
394 public function get_marker($color) {
395 if (is_file($this->markpath . $color . '.png')) {
396 return $this->markurl . $color . '.png';
397 }
398 return plugins_url('/markers/ffffff.png', __FILE__);
399 }
400
401 /**
402 * Enqueue CSS files
403 */
404 public function load_styles() {
405 //CSS
406 if(!empty($this->settings['customcss'])){
407 wp_enqueue_style('event-post-custom', $this->settings['customcss']);
408 }
409 elseif(is_file(get_stylesheet_directory().'/event-post.css') || is_file(get_template_directory().'/event-post.css')){
410 wp_enqueue_style('event-post-custom', get_theme_file_uri('event-post.css'));
411 }
412 else{
413 wp_register_style('event-post', plugins_url('/css/event-post.css', __FILE__), false, filemtime( "{$this->plugin_path}/css/event-post.css" ));
414 wp_enqueue_style('event-post');
415 }
416
417 // Lib scripts
418 wp_enqueue_style('openlayers', plugins_url('/css/ol.css', __FILE__), false, filemtime( "{$this->plugin_path}/css/ol.css" ));
419 wp_enqueue_style('dashicons', includes_url('/css/dashicons.min.css'));
420 }
421 /**
422 * Enqueue Editor style
423 */
424 public function editor_styles() {
425 add_editor_style( plugins_url('/css/event-post.css', __FILE__) );
426 }
427
428 /**
429 * Enqueue JS files
430 */
431 public function load_scripts($deps = array('jquery')) {
432 // JS
433 wp_enqueue_script('jquery', false, false, false, true);
434 wp_enqueue_script('event-post', plugins_url('/js/event-post.min.js', __FILE__), $deps, filemtime( "{$this->plugin_path}/js/event-post.min.js" ), true);
435 $maps = $this->maps;
436 foreach($maps as $m=>$map){
437 if(isset($map['api_param']) && $this->settings['tile_api_key']){
438 foreach($map['urls'] as $i=>$url){
439 $maps[$m]['urls'][$i] = add_query_arg($map['api_param'], $this->settings['tile_api_key'], $url);
440 }
441 }
442 }
443 wp_localize_script('event-post', 'eventpost_params', array(
444 'imgpath' => plugins_url('/img/', __FILE__),
445 'maptiles' => $maps,
446 'defaulttile' => $this->settings['tile'],
447 'zoom' => $this->settings['zoom'],
448 'ajaxurl' => admin_url() . 'admin-ajax.php',
449 'map_interactions'=>$this->map_interactions,
450 ));
451 }
452 /**
453 * Enqueue JS files for maps
454 */
455 public function load_map_scripts() {
456 // JS
457 wp_enqueue_script('openlayers', plugins_url('/js/ol.js', __FILE__), false, filemtime( "{$this->plugin_path}/js/ol.js" ), true);
458 $this->load_scripts(array('jquery', 'openlayers'));
459 if(is_admin()){
460 $this->admin_scripts(array('jquery', 'openlayers'));
461 }
462 }
463
464 /**
465 * Enqueue CSS files in admin
466 */
467 public function admin_head() {
468 $page = basename($_SERVER['SCRIPT_NAME']);
469 if( $page!='post-new.php' && !($page=='post.php' && filter_input(INPUT_GET, 'action')=='edit') && !($page=='options-general.php' && filter_input(INPUT_GET, 'page')=='event-settings') ){
470 return;
471 }
472 wp_enqueue_style('openlayers', plugins_url('/css/ol.css', __FILE__), false, filemtime( "{$this->plugin_path}/css/ol.css" ));
473 wp_enqueue_style('jquery-ui', plugins_url('/css/jquery-ui.css', __FILE__), false, filemtime( "{$this->plugin_path}/css/jquery-ui.css" ));
474 wp_enqueue_style('event-post-admin', plugins_url('/css/event-post-admin.css', __FILE__), false, filemtime( "{$this->plugin_path}/css/event-post-admin.css" ));
475 }
476
477 /**
478 * Enqueue JS files in admin
479 */
480 public function admin_scripts($deps = array('jquery'), $force=false) {
481 $page = basename($_SERVER['SCRIPT_NAME']);
482 if(!$force && $page!='post-new.php' && !($page=='post.php' && filter_input(INPUT_GET, 'action')=='edit') && !($page=='options-general.php' && filter_input(INPUT_GET, 'page')=='event-settings')){
483 return;
484 }
485 wp_enqueue_script('jquery');
486 wp_enqueue_script('jquery-effects-core');
487 wp_enqueue_script('jquery-effects-shake');
488 if(!is_array($deps)){
489 $deps = array('jquery');
490 }
491 if($this->settings['datepicker']=='simple' || !is_admin() || (isset($_GET['page']) && $_GET['page']=='event-settings')){
492 wp_enqueue_script('jquery-ui-datepicker');
493 $deps[] = 'jquery-ui-datepicker';
494 }
495 wp_enqueue_script('event-post-admin', plugins_url('/js/event-post-admin.min.js', __FILE__), $deps, filemtime( "{$this->plugin_path}/js/event-post-admin.min.js" ), true);
496 $language = get_bloginfo('language');
497 if (strpos($language, '-') > -1) {
498 $language = strtolower(substr($language, 0, 2));
499 }
500 wp_localize_script('event-post-admin', 'eventpost', array(
501 'ajaxurl' => admin_url('admin-ajax.php'),
502 'imgpath' => plugins_url('/img/', __FILE__),
503 'date_choose' => '<span class="screen-reader-text">'.__('Choose', 'event-post').'</span><i class="dashicons dashicons-calendar-alt"></i>',
504 'date_format' => __('yy-mm-dd', 'event-post'),
505 'more_icons' => __('More icons', 'event-post'),
506 'pick_a_date'=>__('Pick a date','event-post'),
507 'use_current_location'=>__('Use my current location','event-post'),
508 'start_drag'=>__('Click to<br>drag the map<br>and change location','event-post'),
509 'empty_address'=>__('Be kind to fill a non empty address:)', 'event-post'),
510 'search'=>__('Type an address', 'event-post'),
511 'stop_drag'=>_x('Done','Stop allowing to drag the map', 'event-post'),
512 'datepickeri18n'=>array(
513 'order'=>__( '%1$s %2$s, %3$s @ %4$s:%5$s', 'event-post'),
514 'day'=>__('Day', 'event-post'),
515 'month'=>__('Month', 'event-post'),
516 'year'=>__('Day', 'event-post'),
517 'hour'=>__('Hour', 'event-post'),
518 'minute'=>__('Minute', 'event-post'),
519 'ok'=>__('OK', 'event-post'),
520 'cancel'=>__('Cancel', 'event-post'),
521 'remove'=>__('Remove', 'event-post'),
522 'edit'=>__('Edit', 'event-post'),
523 'months'=>$this->NomDuMois,
524 ),
525 'META_START' => $this->META_START,
526 'META_END' => $this->META_END,
527 'META_ADD' => $this->META_ADD,
528 'META_LAT' => $this->META_LAT,
529 'META_LONG' => $this->META_LONG,
530 'META_STATUS' => $this->META_STATUS,
531 'META_ATTENDANCE_MODE' => $this->META_ATTENDANCE_MODE,
532 'lang'=>$language,
533 'maptiles' => $this->maps,
534 'defaulttile' => $this->settings['tile']
535 ));
536 }
537 function scripts_edit() {
538 // load only when editing a supported post type
539 $current_post_type = isset($_GET['post_type']) ? $_GET['post_type'] : 'post';
540 if ( in_array( $current_post_type, $this->settings['posttypes'] ) ) {
541 wp_enqueue_script( 'eventpost-inline-edit', plugins_url( 'js/inline-edit.min.js', __FILE__ ), array( 'jquery', 'inline-edit-post' ), '', true );
542 wp_localize_script('eventpost-inline-edit', 'eventpost_inline_edit', array(
543 'quick'=>$this->quick_edit_fields,
544 'bulk'=>$this->bulk_edit_fields
545 ));
546 }
547 }
548
549 function get_rich_result($event){
550 /**
551 * https://search.google.com/test/rich-results
552 {
553 "@context": "https://schema.org",
554 "@type": "Event",
555 "name": "The Adventures of Kira and Morrison",
556 "startDate": "2025-07-21T19:00",
557 "endDate": "2025-07-21T23:00",
558 "eventStatus": "https://schema.org/EventScheduled",
559 "eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
560 "location": {
561 "@type": "VirtualLocation",
562 "url": "https://operaonline.stream5.com/"
563 },
564 "image": [
565 "https://example.com/photos/1x1/photo.jpg",
566 "https://example.com/photos/4x3/photo.jpg",
567 "https://example.com/photos/16x9/photo.jpg"
568 ],
569 "description": "The Adventures of Kira and Morrison is coming to Snickertown in a can’t miss performance.",
570 "offers": {
571 "@type": "Offer",
572 "url": "https://www.example.com/event_offer/12345_201803180430",
573 "price": "30",
574 "priceCurrency": "USD",
575 "availability": "https://schema.org/InStock",
576 "validFrom": "2024-05-21T12:00"
577 },
578 "performer": {
579 "@type": "PerformingGroup",
580 "name": "Kira and Morrison"
581 }
582 }
583 */
584 $location_virtual = array(
585 '@type'=>'VirtualLocation',
586 'url'=>$event->virtual_location,
587 );
588 $physical_location = array(
589 '@type'=>'place',
590 'name'=>$event->address,
591 'address'=>$event->address,
592 'geo'=>array(
593 '@type'=>'GeoCoordinates',
594 'latitude'=>$event->lat,
595 'longitude'=>$event->long,
596 ),
597 );
598 $min = 60 * get_option('gmt_offset');
599 $sign = $min < 0 ? "-" : "+";
600 $absmin = abs($min);
601 $gmt_offset = sprintf("%s%02d:%02d", $sign, $absmin/60, $absmin%60);
602 $time_format = (is_numeric($event->time_start) && is_numeric($event->time_end) && date('H:i', $event->time_start) != date('H:i', $event->time_end) && date('H:i', $event->time_start) != '00:00' && date('H:i', $event->time_end) != '00:00') ? 'Y-m-d\Th:i:00'.$gmt_offset : 'Y-m-d';
603
604 return apply_filters('event-post-rich-result', array(
605 '@context'=>'https://schema.org',
606 '@type'=>'event',
607 'name'=>$event->post_title,
608 'datePublished'=>str_replace(' ', 'T', $event->post_date_gmt).$gmt_offset,
609 'dateModified'=>str_replace(' ', 'T', $event->post_modified_gmt).$gmt_offset,
610 'startDate'=>$event->time_start ? date($time_format, $event->time_start) : null,
611 'endDate'=>$event->time_end ? date($time_format, $event->time_end) : null,
612 'eventStatus'=>$event->status,
613 'eventAttendanceMode'=>$event->attendance_mode,
614 'location'=> ($event->attendance_mode == 'MixedEventAttendanceMode') ? array($location_virtual,$physical_location) : ($event->attendance_mode == 'OnlineEventAttendanceMode' ? $location_virtual : $physical_location),
615 'image'=> has_post_thumbnail($event->ID) ? array(
616 get_the_post_thumbnail_url($event->ID, 'post-thumbnail'),
617 get_the_post_thumbnail_url($event->ID, 'medium'),
618 get_the_post_thumbnail_url($event->ID, 'large'),
619 get_the_post_thumbnail_url($event->ID, 'full'),
620 ) : null,
621 'description'=>$event->post_excerpt,
622 ), $event);
623 }
624
625 function wpseo_schema_webpage($rich_result){
626 $event = $this->retreive();
627 if ($event->time_start != '' && $event->time_end != '') {
628 $rich_result = array_merge($rich_result, $this->get_rich_result($event));
629 }
630 $this->is_schema_output = true;
631 return $rich_result;
632 }
633
634 /**
635 * Add custom header meta for single events
636 */
637 public function single_header() {
638 if (is_single()) {
639 $twitter_label_id=0;
640 $event = $this->retreive();
641 $has_location = $has_time = false;
642 if ($event->address != '' || ($event->lat != '' && $event->long != '')) {
643 $twitter_label_id++;
644 $has_location = true;
645 ?>
646 <meta name="geo.placename" content="<?php echo esc_attr($event->address) ?>" />
647 <meta name="geo.position" content="<?php echo esc_attr($event->lat) ?>;<?php echo esc_attr($event->long) ?>" />
648 <meta name="ICBM" content="<?php echo $event->lat ?>;<?php echo esc_attr($event->long) ?>" />
649 <meta property="place:location:latitude" content="<?php echo esc_attr($event->lat) ?>" />
650 <meta property="place:location:longitude" content="<?php echo esc_attr($event->long) ?>" />
651 <meta name="twitter:label<?php echo $twitter_label_id; ?>" content="<?php _e('Location', 'event-post'); ?>"/>
652 <meta name="twitter:data<?php echo $twitter_label_id; ?>" content="<?php echo esc_attr($event->address) ?>"/>
653 <?php
654 }
655 if ($event->start != '' && $event->end != '') {
656 $has_time = true;
657 $twitter_label_id++;
658 ?>
659 <meta name="datetime-coverage-start" content="<?php echo date('c', $event->time_start) ?>" />
660 <meta name="datetime-coverage-end" content="<?php echo date('c', $event->time_end) ?>" />
661 <meta name="twitter:label<?php echo $twitter_label_id; ?>" content="<?php _e('Date', 'event-post'); ?>"/>
662 <meta name="twitter:data<?php echo $twitter_label_id; ?>" content="<?php echo esc_attr($this->human_date($event->time_start)) ?>"/>
663 <?php
664 }
665 if(($has_location || $has_time) && !$this->is_schema_output){
666 $rich_result = $this->get_rich_result($event);
667 $this->is_schema_output = true;
668 ?>
669 <script type="application/ld+json"><?php echo json_encode($rich_result); ?></script>
670 <?php
671 }
672
673 }
674 }
675
676 /**
677 *
678 * @param type $str
679 * @return string
680 * @since 5.0.1
681 */
682 public function date_cleanup($str){
683 return trim(str_replace(array('0', ' ', ':', '-'), '', $str));
684 }
685
686 /**
687 *
688 * @param string $str
689 * @return boolean
690 */
691 public function dateisvalid($str) {
692 return is_string($str) && $this->date_cleanup($str) != '';
693 }
694
695 /**
696 *
697 * @param string $date
698 * @param string $sep
699 * @return string
700 */
701 public function parsedate($date, $sep = '') {
702 if (!empty($date)) {
703 return substr($date, 0, 10) . $sep . substr($date, 11, 8);
704 } else {
705 return '';
706 }
707 }
708
709 /**
710 *
711 * @param mixed $date
712 * @param string $format
713 * @return type
714 */
715 public function human_date($date, $format = 'l j F Y') {
716 if($this->settings['dateforhumans']){
717 if (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y')) {
718 return __('today', 'event-post');
719 } elseif (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y', strtotime('+1 day'))) {
720 return __('tomorrow', 'event-post');
721 } elseif (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y', strtotime('-1 day'))) {
722 return __('yesterday', 'event-post');
723 }
724 }
725 return date_i18n($format, $date);
726 }
727
728 /**
729 *
730 * @param timestamp $time_start
731 * @param timestamp $time_end
732 * @return string
733 */
734 public function delta_date($time_start, $time_end){
735 if(!$time_start || !$time_end){
736 return;
737 }
738
739 $from_to_days = _x('%1$sfrom%2$s %3$s %4$sto%5$s %6$s', 'Days', 'event-post');
740 $single_day_at = _x('%1$s%2$s,%3$s %4$s', 'From/To single day at time', 'event-post');
741 $from_to_hours = _x('%1$sfrom%2$s %3$s %4$sto%5$s %6$s', 'Hours', 'event-post');
742 $at_time = _x('%1$sat%2$s %3$s', 'Time', 'event-post');
743
744 //Display dates
745 $dates="\t\t\t\t".'<div class="event_date" data-start="' . $this->human_date($time_start) . '" data-end="' . $this->human_date($time_end) . '">';
746 // Same day
747 if (date('Ymd', $time_start) == date('Ymd', $time_end)) {
748 $dates.= "\n\t\t\t\t\t\t\t".'<time itemprop="dtstart" datetime="' . date_i18n('c', $time_start) . '">'
749 . '<span class="date date-single">' . $this->human_date($time_end, $this->settings['dateformat']) . "</span>";
750 if (date('H:i', $time_start) != date('H:i', $time_end) && date('H:i', $time_start) != '00:00' && date('H:i', $time_end) != '00:00') {
751 $dates.= ' '.sprintf(
752 $from_to_hours,
753 '<span class="linking_word linking_word-from">',
754 '</span>',
755 '<span class="time time-start">' . date_i18n($this->settings['timeformat'], $time_start) . '</span>',
756 '<span class="linking_word linking_word-to">',
757 '</span>',
758 '<span class="time time-end">' . date_i18n($this->settings['timeformat'], $time_end) . '</span>'
759 );
760 }
761 elseif (date('H:i', $time_start) != '00:00') {
762 $dates.= ' '.sprintf(
763 $at_time,
764 '<span class="linking_word">',
765 '</span>',
766 '<span class="time time-single">' . date_i18n($this->settings['timeformat'], $time_start) . '</span>'
767 );
768 }
769 $dates.="\n\t\t\t\t\t\t\t".'</time>';
770 }
771 // Not same day
772 else {
773 $dates.= ' '.sprintf(
774 $from_to_days,
775 '<span class="linking_word linking_word-from">',
776 '</span>',
777 '<time class="date date-start" itemprop="dtstart" datetime="' . date('c', $time_start) . '">'
778 . ((date('H:i:s', $time_start) != '00:00:00' || date('H:i:s', $time_end) != '00:00:00')
779 ? sprintf($single_day_at, '<span class="date">'.$this->human_date($time_start, $this->settings['dateformat']).'</span>', '<span class="linking_word">', '</span>', '<span class="time">'.date_i18n($this->settings['timeformat'], $time_start).'</span>')
780 : $this->human_date($time_start, $this->settings['dateformat'])
781 )
782 . '</time>',
783 '<span class="linking_word linking_word-to">',
784 '</span>',
785 '<time class="date date-to" itemprop="dtend" datetime="' . date('c', $time_end) . '">'
786 . ((date('H:i:s', $time_start) != '00:00:00' || date('H:i:s', $time_end) != '00:00:00')
787 ? sprintf($single_day_at, '<span class="date">'.$this->human_date($time_end, $this->settings['dateformat']).'</span>', '<span class="linking_word">', '</span>', '<span class="time">'.date_i18n($this->settings['timeformat'], $time_end).'</span>')
788 : $this->human_date($time_end, $this->settings['dateformat'])
789 )
790 . '</time>'
791 );
792 }
793 $dates.="\n\t\t\t\t\t\t".'</div><!-- .event_date -->';
794 return $dates;
795 }
796
797 /**
798 *
799 * @param WP_Post object $post
800 * @param mixed $links
801 * @return string
802 */
803 public function print_date($post = null, $links = 'deprecated', $context='') {
804 $dates = '';
805 $event = $this->retreive($post);
806 if ($event->start != '' && $event->end != '') {
807
808 $dates.=$this->delta_date($event->time_start, $event->time_end);
809 if( // Status setting
810 $this->settings['displaystatus'] == 'both' ||
811 ($this->settings['displaystatus'] == 'single' && is_single() ) ||
812 ($this->settings['displaystatus'] == 'list' && !is_single() )
813 ){
814 $dates.='<span class="eventpost-status">'.$this->statuses[$event->status].'</span>';
815 }
816 $timezone_string = get_option('timezone_string');
817 $gmt_offset = $gmt = $this->get_gmt_offset();
818
819 if (
820 !is_admin()
821 && ( // Export when setting
822 $this->settings['export_when'] == 'both' ||
823 ( $this->settings['export_when'] == 'future' && $this->is_future($event) ) ||
824 ( $this->settings['export_when'] == 'past' && $this->is_past($event) )
825 )
826 && ( // Export setting
827 $this->settings['export'] == 'both' ||
828 ($this->settings['export'] == 'single' && is_single() ) ||
829 ($this->settings['export'] == 'list' && !is_single() )
830 )
831 ) {
832 // Export event
833 $title = urlencode($post->post_title);
834 $address = urlencode($post->address);
835 $desc = urlencode($event->post_excerpt."\\n\\n".$post->permalink);
836 $allday = ($post->time_start && $post->time_end && date('H:i:s', $post->time_start) == '00:00:00' && date('H:i:s', $post->time_end) == '00:00:00');
837 $d_s = date("Ymd", $event->time_start) . ($allday ? '' : 'T' . date("His", $event->time_start));
838 $d_e = date("Ymd", $event->time_end) . ($allday ? '' : 'T' . date("His", $event->time_end));
839 $uid = $post->ID . '-' . $post->blog_id;
840 $url = $event->permalink;
841
842 // format de date ICS
843 $permalink_structure = get_option( 'permalink_structure' );
844 if($permalink_structure != ""){
845 $ics_url = site_url('eventpost/'.$event->ID.'.ics');
846 $vcs_url = site_url('eventpost/'.$event->ID.'.vcs');
847 }
848 else{
849 $ics_url = add_query_arg(array('action'=>'EventPostExport', 'event_id'=>$event->ID, 'format'=>'ics'), admin_url('admin-ajax.php'));
850 $vcs_url = add_query_arg(array('action'=>'EventPostExport', 'event_id'=>$event->ID, 'format'=>'vcs'), admin_url('admin-ajax.php'));
851
852 }
853
854 // format de date Google cal
855 //$google_url = 'https://www.google.com/calendar/event?action=TEMPLATE&amp;text=' . $title . '&amp;dates=' . $d_s . 'Z/' . $d_e . 'Z&amp;details=' . $url . '&amp;ctz='.$timezone_string.'&amp;location=' . $address . '&amp;trp=false&amp;sprop=&amp;sprop=name';
856 $google_url = add_query_arg(array(
857 'action'=>'TEMPLATE',
858 'trp'=>'false',
859 'sprop'=>'name',
860 'text'=>$title,
861 'dates'=>$d_s.'/'.$d_e.'', // Removed Z to fix TZ issue
862 'location'=>$address,
863 'details'=>$desc,
864 'gmt'=> urlencode($gmt_offset)
865 ), 'https://www.google.com/calendar/event');
866 if(!empty($timezone_string)){
867 $google_url = add_query_arg(array(
868 'ctz'=>$timezone_string,
869 ), $google_url);
870 }
871
872 $dates.='
873 <span class="eventpost-date-export">
874 <a href="' . $ics_url . '" class="event_link event-export ics" target="_blank" title="' . __('Download ICS file', 'event-post') . '">ical</a>
875 <a href="' . $google_url . '" class="event_link event-export gcal" target="_blank" title="' . __('Add to Google calendar', 'event-post') . '">Google</a>
876 <a href="' . $vcs_url . '" class="event_link event-export vcs" target="_blank" title="' . __('Add to Outlook', 'event-post') . '">outlook</a>
877 <i class="dashicons-before dashicons-calendar"></i>
878 </span>';
879 }
880 }
881 return apply_filters('eventpost_printdate', $dates);
882 }
883
884 /**
885 *
886 * @param WP_Post object $post
887 * @return string
888 */
889 public function print_location($post=null, $context='') {
890 $location = '';
891 if ($post == null)
892 $post = get_post();
893 elseif (is_numeric($post)) {
894 $post = get_post($post);
895 }
896 if (!isset($post->start)) {
897 $post = $this->retreive($post);
898 }
899 $address = $post->address;
900 $lat = $post->lat;
901 $long = $post->long;
902 $color = $post->color;
903 $virtual_location = $post->virtual_location;
904 $attendance_mode = $post->attendance_mode;
905
906 if ($this->is_online($post) && $virtual_location) {
907 $location.="\t\t\t\t".'<div><a href="'.esc_url($virtual_location).'" class="eventpost-virtual-location-link" target="_blank" rel="noopener">'
908 .__('Join link', 'event-post')
909 .'</a></div>'
910 ."\n";
911 }
912 if ($this->is_offline($post) && ($address != '' || ($lat != '' && $long != ''))) {
913 $location.="\t\t\t\t".'<address';
914 if ($lat != '' && $long != '') {
915 $location.=' data-id="' . $post->ID . '" data-latitude="' . $lat . '" data-longitude="' . $long . '" data-marker="' . $this->get_marker($color) . '" ';
916 }
917 $location.=' itemprop="adr" class="eventpost-address">'
918 . "\n\t\t\t\t\t\t\t".'<span>'
919 . "\n".$address
920 . "\n\t\t\t\t\t\t\t". '</span>';
921 if ($context=='single' && $lat != '' && $long != '') {
922 $location.="\n\t\t\t\t\t\t\t".'<a class="event_link gps dashicons-before dashicons-location-alt" href="https://www.openstreetmap.org/?lat=' . $lat .'&amp;lon=' . $long . '&amp;zoom=13" target="_blank" itemprop="geo">' . __('Map', 'event-post') . '</a>';
923 }
924 $location.="\n\t\t\t\t\t\t".'</address>';
925 if (wp_is_mobile() && $lat != '' && $long != '') {
926 $location.="\n\t\t\t\t\t\t".'<a class="event_link gps-geo-link" href="geo:' . $lat . ',' . $long . '" target="_blank" itemprop="geo"><i class="dashicons-before dashicons-location"></i> ' . __('Open in app', 'event-post') . '</a>';
927 }
928 }
929
930 return apply_filters('eventpost_printlocation', $location);
931 }
932
933 /**
934 *
935 * @param WP_Post object $post
936 * @return string
937 */
938 public function print_categories($post=null, $context='') {
939 if ($post == null)
940 $post = get_post();
941 elseif (is_numeric($post)) {
942 $post = get_post($post);
943 }
944 if (!isset($post->start)) {
945 $post = $this->retreive($post);
946 }
947 $cats = '';
948 $categories = $post->categories;
949 if ($categories) {
950 $cats.="\t\t\t\t".'<span class="event_category"';
951 $color = $post->color;
952 if ($color != '') {
953 $cats.=' style="color:#' . $color . '"';
954 }
955 $cats.='>';
956 foreach ($categories as $category) {
957 $cats .= $category->name . ' ';
958 }
959 $cats.='</span>';
960 }
961 return $cats;
962 }
963
964 /**
965 * Generate, return or output date event datas
966 * @param WP_Post object $post
967 * @param string $class
968 * @filter eventpost_get_single
969 * @return string
970 */
971 public function get_single($post = null, $class = '', $context='') {
972 if ($post == null) {
973 $post = $this->retreive();
974 }
975 $datas_date = $this->print_date($post, null, $context);
976 $datas_cat = $this->print_categories($post, $context);
977 $datas_loc = $this->print_location($post, $context);
978 $classes = array(
979 'event_data',
980 'status-'.$post->status,
981 'location-type-'.$post->attendance_mode,
982 $class
983 );
984 if ($datas_date != '' || $datas_loc != '') {
985 $rgb = $this->hex2dec($post->color);
986 return '<div class="' . implode(' ', $classes) . '" style="border-left-color:#' . $post->color . ';background:rgba(' . $rgb['R'] . ',' . $rgb['G'] . ',' . $rgb['B'] . ',0.1)" itemscope itemtype="http://microformats.org/profile/hcard">'
987 . apply_filters('eventpost_get_single', $datas_date . $datas_cat . $datas_loc, $post)
988 . '</div>';
989 }
990 return '';
991 }
992
993 /**
994 * Displays dates of a gieven post
995 * @param WP_Post object $post
996 * @param string $class
997 * @return string
998 */
999 public function get_singledate($post = null, $class = '', $context='') {
1000 return '<div class="event_data event_date ' . $class . '" itemscope itemtype="http://microformats.org/profile/hcard">' . "\n\t\t".$this->print_date($post, null, $context) . "\n\t\t\t\t\t".'</div><!-- .event_date -->';
1001 }
1002
1003 /**
1004 * Displays coloured terms of a given post
1005 * @param WP_Post object $post
1006 * @param string $class
1007 * @return string
1008 */
1009 public function get_singlecat($post = null, $class = '', $context='') {
1010 return '<div class="event_data event_category ' . $class . '" itemscope itemtype="http://microformats.org/profile/hcard">' . "\n\t\t".$this->print_categories($post, $context) . "\n\t\t\t\t\t".'</div><!-- .event_category -->';
1011 }
1012
1013 /**
1014 * Displays location of a given post
1015 * @param WP_Post object $post
1016 * @param string $class
1017 * @return string
1018 */
1019 public function get_singleloc($post = null, $class = '', $context='') {
1020 return '<div class="event_data event_location ' . $class . '" itemscope itemtype="http://microformats.org/profile/hcard">' . "\n\t\t".$this->print_location($post, $context) . "\n\t\t\t\t\t".'</div><!-- .event_location -->';
1021 }
1022
1023 /**
1024 * Uses `the_content` filter to add event details before or after the content of the current post
1025 * @param string $content
1026 * @return string
1027 */
1028 public function display_single($content) {
1029 if (is_page() || !is_single() || is_home() || !in_the_loop() || !is_main_query()){
1030 return $content;
1031 }
1032
1033 $post = $this->retreive();
1034 $eventbar = apply_filters('eventpost_contentbar', $this->get_single($post, 'event_single', 'single'), $post);
1035 if($this->settings['singlepos']=='before'){
1036 $content=$eventbar.$content;
1037 }
1038 elseif($this->settings['singlepos']=='after'){
1039 $content.=$eventbar;
1040 }
1041 $this->load_map_scripts();
1042 return $content;
1043 }
1044
1045 /**
1046 * Outputs events details (dates, geoloc, terms) of given post
1047 * @param WP_Post object $post
1048 * @echoes string
1049 * @return void
1050 */
1051 public function print_single($post = null) {
1052 echo $this->get_single($post);
1053 }
1054
1055 /**
1056 * Alter the post title in order to add icons if needed
1057 * @param string $title
1058 * @return string
1059 */
1060 public function the_title($title, $post_id = null){
1061 if(!$post_id || !in_the_loop() || !$this->settings['loopicons']){
1062 return $title;
1063 }
1064 $icons_ = array(
1065 // Emojis
1066 1=>array('🗓', '🗺'),
1067 // Dashicons
1068 2=>array('<span class="dashicons dashicons-calendar"></span>', '<span class="dashicons dashicons-location"></span>'),
1069 );
1070
1071 $event = $this->retreive($post_id);
1072 if(!empty($event->start)){
1073 $title .= ' '.$icons_[$this->settings['loopicons']][0];
1074 }
1075 if(!empty($event->lat) && !empty($event->long)){
1076 $title .= ' '.$icons_[$this->settings['loopicons']][1];
1077 }
1078 return $title;
1079 }
1080
1081
1082 /**
1083 * Return an HTML list of events
1084 *
1085 * @filter eventpost_params($defaults, 'list_events')
1086 * @filter eventpost_listevents
1087 * @filter eventpost_item_scheme_entities
1088 * @filter eventpost_item_scheme_values
1089 *
1090 * @param array $atts
1091 * @param string $id
1092 * @param string $context
1093 * @return string
1094 */
1095 public function list_events($atts, $id = 'event_list', $context='') {
1096
1097 $ep_settings = $this->settings;
1098 $defaults = array(
1099 'nb' => 0,
1100 'type' => 'div',
1101 'future' => true,
1102 'past' => false,
1103 'geo' => 0,
1104 'width' => '',
1105 'height' => '',
1106 'list' => 0,
1107 'zoom' => '',
1108 'map_position' => 'false',
1109 'latitude' => '',
1110 'longitude' => '',
1111 'tile' => $ep_settings['tile'],
1112 'pop_element_schema' => 'false',
1113 'htmlPop_element_schema' => '',
1114 'title' => '',
1115 'before_title' => '<h3>',
1116 'after_title' => '</h3>',
1117 'cat' => '',
1118 'tag' => '',
1119 'tax_name' => '',
1120 'tax_term' => '',
1121 'events' => '',
1122 'style' => '',
1123 'thumbnail' => '',
1124 'thumbnail_size' => '',
1125 'excerpt' => '',
1126 'orderby' => 'meta_value',
1127 'order' => 'ASC',
1128 'class' => '',
1129 'className' => '',
1130 'container_schema' => $this->list_shema['container'],
1131 'item_schema' => $this->list_shema['item'],
1132 'pages' => false,
1133 );
1134 // Map UI options
1135 foreach($this->map_interactions as $int_key=>$int_name){
1136 $defaults[$int_key]=true;
1137 }
1138 $atts = shortcode_atts(apply_filters('eventpost_params', $defaults, 'list_events'), $atts);
1139
1140 extract($atts);
1141 if (!is_array($events)) {
1142 $events = $this->get_events($atts);
1143 }
1144 $ret = '';
1145 $this->list_id++;
1146 if (sizeof($events) > 0) {
1147 if (!empty($title)) {
1148 $ret.= html_entity_decode($before_title) . $title . html_entity_decode($after_title);
1149 }
1150
1151 $child = ($type == 'ol' || $type == 'ul') ? 'li' : 'div';
1152
1153 $html = '';
1154
1155 if($id=='event_geolist'){
1156 $this->load_map_scripts();
1157 $html.=sprintf('<%1$s class="event_geolist_icon_loader"><p><span class="dashicons dashicons-location-alt"></span></p><p class="screen-reader-text">'.__('An events map', 'event-post').'</p></%1$s>', $type);
1158 }
1159
1160 foreach ($events as $event) {
1161 $class_item = array(
1162 $this->is_future($event) ? 'event_future' : 'event_past',
1163 'status-'.$event->status,
1164 'location-type-'.$event->attendance_mode,
1165 );
1166 if ($ep_settings['emptylink'] == 0 && empty($event->post_content)) {
1167 $event->permalink = '#' . $id . $this->list_id;
1168 }
1169 elseif(empty($event->permalink)){
1170 $event->permalink=$event->guid;
1171 }
1172 $html.=str_replace(
1173 apply_filters('eventpost_item_scheme_entities', array(
1174 '%child%',
1175 '%class%',
1176 '%color%',
1177 '%event_link%',
1178 '%event_thumbnail%',
1179 '%event_title%',
1180 '%event_date%',
1181 '%event_cat%',
1182 '%event_location%',
1183 '%event_excerpt%'
1184 )), apply_filters('eventpost_item_scheme_values', array(
1185 $child,
1186 implode(' ', $class_item),
1187 $event->color,
1188 $event->permalink,
1189 $thumbnail == true ? '<span class="event_thumbnail_wrap">' . get_the_post_thumbnail($event->root_ID, !empty($thumbnail_size) ? $thumbnail_size : 'thumbnail', array('class' => 'attachment-thumbnail wp-post-image event_thumbnail')) . '</span>' : '',
1190 $event->post_title,
1191 $this->get_singledate($event, '', $context),
1192 $this->get_singlecat($event, '', $context),
1193 $this->get_singleloc($event, '', $context),
1194 $excerpt == true && $event->post_excerpt!='' ? '<span class="event_exerpt">'.$event->post_excerpt.'</span>' : '',
1195 ), $event), $item_schema
1196 );
1197 }
1198 $attributes = '';
1199 if($id == 'event_geolist'){
1200 if($height==''){
1201 $height = '300px';
1202 }
1203 if($width==''){
1204 $width = '100%';
1205 }
1206 $attributes = 'data-tile="'.$tile.'" data-width="'.$width.'" data-height="'.$height.'" data-zoom="'.$zoom.'" data-map_position="'.$map_position.'" data-latitude="'.$latitude.'" data-longitude="'.$longitude.'" data-pop_element_schema="'.$pop_element_schema.'" data-htmlPop_element_schema="'.esc_attr($htmlPop_element_schema).'" data-list="'.$list.'" data-disabled-interactions="';
1207 // add data-position avec ma variables
1208 foreach($this->map_interactions as $int_key=>$int_name){
1209 $attributes.=$atts[$int_key]==false ? $int_key.', ' : '';
1210 }
1211 $attributes.='"';
1212 }
1213 $pagination = '';
1214 if($pages && $this->pagination){
1215 global $wp_rewrite;
1216 $paged = ( get_query_var( 'page' ) ) ? absint( get_query_var( 'page' ) ) : 1;
1217 $pagination = paginate_links( array(
1218 'prev_text' => __('« Previous Events', 'event-post'),
1219 'next_text' => __('Next Events »', 'event-post'),
1220 'current' => $paged,
1221 'total' => $this->pagination['max_num_pages'],
1222 )
1223 );
1224 }
1225 $ret.=str_replace(
1226 array(
1227 '%type%',
1228 '%id%',
1229 '%class%',
1230 '%listid%',
1231 '%style%',
1232 '%attributes%',
1233 '%list%',
1234 '%pagination%',
1235 ), array(
1236 $type,
1237 $id,
1238 $class.($className ? ' '.$className : '').($id == 'event_geolist' && $list ? ' has-list list-'.$list : ' no-list'),
1239 $id . $this->list_id,
1240 (!empty($width) ? 'width:' . $width . ';' : '') . (!empty($height) ? 'height:' . $height . ';' : '') . $style,
1241 $attributes,
1242 $html,
1243 $pagination,
1244 ), $container_schema
1245 );
1246 }
1247 elseif(filter_input(INPUT_POST, 'action')=='bulk_do_shortcode'){
1248 return '<div class="event_geolist_icon_loader"><p><span class="dashicons dashicons-calendar"></span></p><p class="screen-reader-text">'.__('An empty list of events', 'event-post').'</p></div>';
1249 }
1250 return apply_filters('eventpost_listevents', $ret, $id.$this->list_id, $atts, $events, $context);
1251 }
1252
1253 /**
1254 * get_events
1255 * @param array $atts
1256 * @filter eventpost_params
1257 * @filter eventpost_get_items
1258 * @return array of post_ids wich are events
1259 */
1260 public function get_events($atts) {
1261 $paged = ( get_query_var( 'page' ) ) ? absint( get_query_var( 'page' ) ) : 1;
1262 $requete = (shortcode_atts(apply_filters('eventpost_params', array(
1263 'nb' => 5,
1264 'future' => true,
1265 'past' => false,
1266 'geo' => 0,
1267 'cat' => '',
1268 'tag' => '',
1269 'date' => '',
1270 'orderby' => 'meta_value',
1271 'orderbykey' => $this->META_START,
1272 'order' => 'ASC',
1273 'tax_name' => '',
1274 'tax_term' => '',
1275 'paged' => $paged,
1276 'post_type'=> $this->settings['posttypes']
1277 ), 'get_events'), $atts));
1278 extract($requete);
1279 wp_reset_query();
1280
1281
1282 $arg = array(
1283 'post_status' => 'publish',
1284 'post_type' => $post_type,
1285 'posts_per_page' => $nb,
1286 'paged' => $paged,
1287 'meta_key' => $orderbykey,
1288 'orderby' => $orderby,
1289 'order' => $order
1290 );
1291
1292 if($tax_name=='category'){
1293 $tax_name='';
1294 $cat=$tax_term;
1295 }
1296 elseif($tax_name=='post-tag'){
1297 $tax_name='';
1298 $tag=$tax_term;
1299 }
1300
1301 // CUSTOM TAXONOMY
1302 if ($tax_name != '' && $tax_term != '') {
1303 $arg['tax_query'] = array(
1304 array(
1305 'taxonomy' => $tax_name,
1306 'field' => 'slug',
1307 'terms' => $tax_term,
1308 ),
1309 );
1310 }
1311 // CAT
1312 if ($cat != '') {
1313 if (preg_match('/[a-zA-Z]/i', $cat)) {
1314 $arg['category_name'] = $cat;
1315 } else {
1316 $arg['cat'] = $cat;
1317 }
1318 }
1319 // TAG
1320 if ($tag != '') {
1321 $arg['tag'] = $tag;
1322 }
1323 // DATES
1324 $meta_query = array(
1325 array(
1326 'key' => $this->META_END,
1327 'value' => '',
1328 'compare' => '!='
1329 ),
1330 array(
1331 'key' => $this->META_END,
1332 'value' => '0:0:00 0:',
1333 'compare' => '!='
1334 ),
1335 array(
1336 'key' => $this->META_END,
1337 'value' => ':00',
1338 'compare' => '!='
1339 ),
1340 array(
1341 'key' => $this->META_START,
1342 'value' => '',
1343 'compare' => '!='
1344 ),
1345 array(
1346 'key' => $this->META_START,
1347 'value' => '0:0:00 0:',
1348 'compare' => '!='
1349 )
1350 );
1351 if ($future == 0 && $past == 0) {
1352 $meta_query = array();
1353 $arg['meta_key'] = null;
1354 $arg['orderby'] = null;
1355 $arg['order'] = null;
1356 }
1357 elseif ($future == 1 && $past == 0) {
1358 $meta_query[] = array(
1359 'key' => $this->META_END,
1360 'value' => current_time('mysql'),
1361 'compare' => '>=',
1362 //'type'=>'DATETIME'
1363 );
1364 }
1365 elseif ($future == 0 && $past == 1) {
1366 $meta_query[] = array(
1367 'key' => $this->META_END,
1368 'value' => current_time('mysql'),
1369 'compare' => '<=',
1370 //'type'=>'DATETIME'
1371 );
1372 }
1373 if ($date != '') {
1374 $date = date('Y-m-d', $date);
1375
1376 $meta_query = array(
1377 array(
1378 'key' => $this->META_END,
1379 'value' => $date . ' 00:00:00',
1380 'compare' => '>=',
1381 'type' => 'DATETIME'
1382 ),
1383 array(
1384 'key' => $this->META_START,
1385 'value' => $date . ' 23:59:59',
1386 'compare' => '<=',
1387 'type' => 'DATETIME'
1388 )
1389 );
1390 }
1391 // GEO
1392 if ($geo == 1) {
1393 $meta_query[] = array(
1394 'key' => $this->META_LAT,
1395 'value' => '',
1396 'compare' => '!='
1397 );
1398 $meta_query[] = array(
1399 'key' => $this->META_LONG,
1400 'value' => '',
1401 'compare' => '!='
1402 );
1403 $arg['meta_key'] = $this->META_LAT;
1404 $arg['orderby'] = 'meta_value';
1405 $arg['order'] = 'DESC';
1406 }
1407
1408 $arg['meta_query'] = $meta_query;
1409
1410 $query_md5 = 'eventpost_' . md5(var_export($requete, true));
1411 // Check if cache is activated
1412 if ($this->settings['cache'] == 1 && false !== ( $cached_events = get_transient($query_md5) )) {
1413 return apply_filters('eventpost_get_items', is_array($cached_events) ? $cached_events : array(), $requete, $arg);
1414 }
1415
1416 $events = apply_filters('eventpost_get', '', $requete, $arg);
1417 if ('' === $events) {
1418 global $wpdb;
1419 $query = new WP_Query($arg);
1420 $events = $wpdb->get_col($query->request);
1421 $this->pagination = array(
1422 'found_posts' => $query->found_posts,
1423 'max_num_pages' => $query->max_num_pages,
1424 );
1425 foreach ($events as $k => $post) {
1426 $event = $this->retreive($post);
1427 $events[$k] = $event;
1428 }
1429 }
1430 if ($this->settings['cache'] == 1){
1431 set_transient($query_md5, $events, 5 * MINUTE_IN_SECONDS);
1432 }
1433 return apply_filters('eventpost_get_items', $events, $requete, $arg);
1434 }
1435
1436 /**
1437 * Checks if the given event is in the future or not
1438 *
1439 * @param object $event
1440 * @param boolean $exact Future status has to be calculated against time or entire day
1441 * @return boolean
1442 */
1443 function is_future($event, $exact=false){
1444 $match = current_time('timestamp');
1445 // if EXACT is false, end date is set to begining of the current day
1446 if(!$exact){
1447 $match = mktime(0, 0, 0, date('m', $match), date('d', $match), date('Y', $match));
1448 }
1449 return ($event->time_end >= $match);
1450 }
1451
1452 /**
1453 * Checks if the given event is completed or not
1454 *
1455 * @param object $event
1456 * @param boolean $exact Past status has to be calculated against time or entire day
1457 * @return boolean
1458 */
1459 function is_past($event, $exact=false){
1460 $match = current_time('timestamp');
1461 // if EXACT is false or full day event, end date is set to end of the current day
1462 if(!$exact || ( date('H:i:s', $event->time_start) == '00:00:00' && date('H:i:s', $event->time_end) == '00:00:00' )){
1463 $match = mktime(23, 59, 59, date('m', $match), date('d', $match), date('Y', $match));
1464 }
1465 return ($event->time_end < $match);
1466 }
1467
1468 function is_online($event){
1469 return (in_array($event->attendance_mode, array('MixedEventAttendanceMode', 'OnlineEventAttendanceMode')));
1470 }
1471
1472 function is_offline($event){
1473 return (in_array($event->attendance_mode, array('MixedEventAttendanceMode', 'OfflineEventAttendanceMode')));
1474 }
1475
1476
1477 /**
1478 *
1479 * @param object $event
1480 * @return object
1481 */
1482 public function retreive($event = null) {
1483 global $EventPost_cache;
1484 $ob = get_post($event);
1485 if(is_object($ob) && $ob->start){
1486 return $ob;
1487 }
1488 if(is_object($ob) && isset($EventPost_cache[$ob->ID])){
1489 return $EventPost_cache[$ob->ID];
1490 }
1491 $ob->start = get_post_meta($ob->ID, $this->META_START, true);
1492 $ob->end = get_post_meta($ob->ID, $this->META_END, true);
1493 if (!$this->dateisvalid($ob->start)){
1494 $ob->start = '';
1495 }
1496 if (!$this->dateisvalid($ob->end)){
1497 $ob->end = '';
1498 }
1499 $ob->root_ID = $ob->ID;
1500 $ob->time_start = !empty($ob->start) ? strtotime($ob->start) : '';
1501 $ob->time_end = !empty($ob->end) ? strtotime($ob->end) : '';
1502 $ob->virtual_location = get_post_meta($ob->ID, $this->META_VIRTUAL_LOCATION, true);
1503 $ob->address = get_post_meta($ob->ID, $this->META_ADD, true);
1504 $ob->lat = get_post_meta($ob->ID, $this->META_LAT, true);
1505 $ob->long = get_post_meta($ob->ID, $this->META_LONG, true);
1506 $ob->attendance_mode = (null != $att_mod = get_post_meta($ob->ID, $this->META_ATTENDANCE_MODE, true)) ? $att_mod : array_keys($this->attendance_modes)[0];
1507 $ob->status = (null != $status = get_post_meta($ob->ID, $this->META_STATUS, true)) ? $status : array_keys($this->statuses)[0];
1508 $ob->color = get_post_meta($ob->ID, $this->META_COLOR, true);
1509 $ob->categories = get_the_category($ob->ID);
1510 $ob->permalink = get_permalink($ob->ID);
1511 $ob->blog_id = get_current_blog_id();
1512 if ($ob->color == ''){
1513 $ob->color = '000000';
1514 }
1515
1516 $EventPost_cache[$ob->ID] = apply_filters('eventpost_retreive', $ob);
1517 return $EventPost_cache[$ob->ID];
1518 }
1519
1520 /**
1521 *
1522 * @param mixte $_term
1523 * @param string $taxonomy
1524 * @param string $post_type
1525 */
1526 public function retreive_term($_term=null, $taxonomy='category', $post_type='post') {
1527 $term = get_term($_term, $taxonomy);
1528
1529 if(!$term){
1530 return $term;
1531 }
1532
1533 $term->start = $term->end = $term->time_start = $term->time_end = Null;
1534
1535 $request = array(
1536 'post_type'=>$post_type,
1537 'tax_name'=>$term->taxonomy,
1538 'tax_term'=>$term->slug,
1539 'future'=>true,
1540 'past'=>true,
1541 'nb'=>-1,
1542 'order'=>'ASC'
1543 );
1544
1545 $events = $this->get_events($request);
1546
1547 $term->events_count = count($events);
1548 if($term->events_count){
1549 $term->start = $events[0]->start;
1550 $term->time_start = $events[0]->time_start;
1551 $term->end = $events[$term->events_count-1]->end;
1552 $term->time_end = $events[$term->events_count-1]->time_end;
1553 }
1554
1555 $request['order']='DESC';
1556 $request['nb']=1;
1557 $request['orderbykey']=$this->META_END;
1558 $events = $this->get_events($request);
1559 if(count($events)){
1560 $term->end = $events[0]->end;
1561 $term->time_end = $events[0]->time_end;
1562 }
1563
1564 return $term;
1565
1566 }
1567
1568 /** ADMIN ISSUES * */
1569
1570 /**
1571 * add custom boxes in posts edit page
1572 */
1573 public function add_custom_box() {
1574 foreach($this->settings['posttypes'] as $posttype){
1575 add_meta_box(
1576 'event_post_date',
1577 __('Event date', 'event-post'),
1578 array(&$this, 'inner_custom_box_date'),
1579 $posttype,
1580 apply_filters('eventpost_add_custom_box_position', $this->settings['adminpos'], $posttype),
1581 'core',
1582 array(
1583 '__block_editor_compatible_meta_box' => true,
1584 )
1585 );
1586 add_meta_box(
1587 'event_post_loc',
1588 __('Location', 'event-post'),
1589 array(&$this, 'inner_custom_box_loc'),
1590 $posttype,
1591 apply_filters('eventpost_add_custom_box_position', $this->settings['adminpos'], $posttype),
1592 'core',
1593 array(
1594 '__block_editor_compatible_meta_box' => true,
1595 )
1596 );
1597 do_action('eventpost_add_custom_box', $posttype);
1598 }
1599 }
1600 /**
1601 * display the date custom box
1602 */
1603 public function inner_custom_box_date() {
1604 wp_nonce_field(plugin_basename(__FILE__), 'eventpost_nonce');
1605 $post_id = get_the_ID();
1606 $event = $this->retreive($post_id);
1607 $start_date = $event->start;
1608 $end_date = $event->end;
1609 $eventcolor = $event->color;
1610
1611 $language = get_bloginfo('language');
1612 if (strpos($language, '-') > -1) {
1613 $language = strtolower(substr($language, 0, 2));
1614 }
1615 $colors = $this->get_colors();
1616 include (plugin_dir_path(__FILE__) . 'views/admin/custombox-date.php');
1617 do_action ('eventpost_custom_box_date', $event);
1618 }
1619 /**
1620 * displays the location custom box
1621 */
1622 public function inner_custom_box_loc($post) {
1623 $event = $this->retreive($post);
1624 include (plugin_dir_path(__FILE__) . 'views/admin/custombox-location.php');
1625 do_action ('eventpost_custom_box_loc', $event);
1626 $this->load_map_scripts();
1627 }
1628
1629 /**
1630 *
1631 * @param string $column_name
1632 * @param boolean $bulk
1633 */
1634 function quick_edit( $column_name, $post_type, $bulk=false) {
1635
1636 if ($bulk) {
1637 static $eventpostprintNonceBulk = TRUE;
1638 if ($eventpostprintNonceBulk) {
1639 $eventpostprintNonceBulk = FALSE;
1640 }
1641 $fields = $this->bulk_edit_fields;
1642 echo '<input type="hidden" name="eventpost-bulk-editor" id="eventpost-bulk-editor" value="eventpost-bulk-editor">';
1643 }
1644 else {
1645 static $eventpostprintNonce = TRUE;
1646 if ($eventpostprintNonce) {
1647 $eventpostprintNonce = FALSE;
1648 }
1649 $fields = $this->quick_edit_fields;
1650 }
1651 wp_nonce_field(plugin_basename(__FILE__), 'eventpost_nonce');
1652 if(isset($fields[$column_name])): ?>
1653 <fieldset class="inline-edit-col-left inline-edit-<?php echo $column_name; ?>">
1654 <div class="inline-edit-group">
1655 <?php foreach ($fields[$column_name] as $fieldname=>$fieldlabel): ?>
1656 <fieldset class="inline-edit-col inline-edit-<?php echo $fieldname; ?>">
1657 <div class="inline-edit-col column-<?php echo $fieldname; ?>">
1658 <label class="inline-edit-group">
1659 <span class="title"><?php echo $fieldlabel; ?></span>
1660 <span class="input-text-wrap">
1661 <?php echo $this->inline_field($fieldname, $bulk); ?>
1662 </span>
1663 </label>
1664 </div>
1665 </fieldset>
1666 <?php endforeach; ?>
1667 </div>
1668 </fieldset>
1669 <?php endif;
1670 }
1671
1672 /**
1673 *
1674 * @param type $fieldname
1675 * @return type
1676 */
1677 function inline_field($fieldname, $bulk){
1678 return apply_filters('eventpost_inline_field', '<input name="'.$fieldname.'" class="eventpost-inline-'.$fieldname.'" value="" type="text">', $fieldname, $bulk);
1679 }
1680
1681 function inline_field_color($html, $fieldname, $bulk){
1682 if($fieldname==$this->META_COLOR){
1683 $colors = $this->get_colors();
1684 $html='';
1685 if($bulk){
1686 $html.= '<span class="eventpost-bulk-colorpicker-button link">'.__('No Change', 'event-post').'</span>';
1687 }
1688 $html .= '<select name="'.$fieldname.'" class="eventpost-inline-colorpicker eventpost-inline-'.$fieldname.' '.($bulk?'is-bulk':'no-bulk').'" >';
1689 if($bulk){
1690 $html.='<option value="false">— '.__('No Change', 'event-post').' —</option>';
1691 }
1692 foreach ($colors as $color=>$image_path){
1693 $html.='<option value="'.$color.'" data-path="'.$image_path.'">'.$color.'</option>';
1694 }
1695 $html.= '</select>';
1696 }
1697 return $html;
1698 }
1699
1700 /**
1701 *
1702 * @param type $column_name
1703 * @param type $post_type
1704 */
1705 function bulk_edit($column_name, $post_type){
1706 $this->quick_edit($column_name, $post_type, true);
1707 }
1708
1709 /**
1710 *
1711 */
1712 function inline_save(){
1713 $post_id = filter_input(INPUT_POST, 'post_ID', FILTER_SANITIZE_NUMBER_INT);
1714 $this->save_postdata($post_id);
1715 }
1716 /**
1717 * When the post is saved, saves our custom data
1718 * @param int $post_id
1719 * @return void
1720 */
1721 public function save_postdata($post_id) {
1722 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE){
1723 return;
1724 }
1725
1726 if (!wp_verify_nonce(filter_input(INPUT_POST, 'eventpost_nonce', FILTER_SANITIZE_STRING), plugin_basename(__FILE__))){
1727 return;
1728 }
1729
1730 // Clean color or no color
1731 if (false !== $color = filter_input(INPUT_POST, $this->META_COLOR, FILTER_SANITIZE_STRING)) {
1732 update_post_meta($post_id, $this->META_COLOR, $color);
1733 }
1734 if (false !== $attendance_mode = filter_input(INPUT_POST, $this->META_ATTENDANCE_MODE, FILTER_SANITIZE_STRING)) {
1735 update_post_meta($post_id, $this->META_ATTENDANCE_MODE, $attendance_mode);
1736 }
1737 if (false !== $status = filter_input(INPUT_POST, $this->META_STATUS, FILTER_SANITIZE_STRING)) {
1738 update_post_meta($post_id, $this->META_STATUS, $status);
1739 }
1740 if (false !== $virtual_location = filter_input(INPUT_POST, $this->META_VIRTUAL_LOCATION, FILTER_SANITIZE_URL)) {
1741 update_post_meta($post_id, $this->META_VIRTUAL_LOCATION, $virtual_location);
1742 }
1743 // Clean date or no date
1744 if ((false !== $start = filter_input(INPUT_POST, $this->META_START, FILTER_SANITIZE_STRING)) &&
1745 (false !== $end = filter_input(INPUT_POST, $this->META_END, FILTER_SANITIZE_STRING)) &&
1746 '' != $start &&
1747 '' != $end) {
1748 update_post_meta($post_id, $this->META_START, substr($start,0,16).':00');
1749 update_post_meta($post_id, $this->META_END, substr($end,0,16).':00');
1750 }
1751 else {
1752 delete_post_meta($post_id, $this->META_START);
1753 delete_post_meta($post_id, $this->META_END);
1754 }
1755
1756 // Clean location or no location
1757 if ((false !== $lat = filter_input(INPUT_POST, $this->META_LAT, FILTER_SANITIZE_STRING)) &&
1758 (false !== $long = filter_input(INPUT_POST, $this->META_LONG, FILTER_SANITIZE_STRING)) &&
1759 '' != $lat &&
1760 '' != $long) {
1761 update_post_meta($post_id, $this->META_ADD, filter_input(INPUT_POST, $this->META_ADD, FILTER_SANITIZE_STRING));
1762 update_post_meta($post_id, $this->META_LAT, $lat);
1763 update_post_meta($post_id, $this->META_LONG, $long);
1764 }
1765 else {
1766 delete_post_meta($post_id, $this->META_ADD);
1767 delete_post_meta($post_id, $this->META_LAT);
1768 delete_post_meta($post_id, $this->META_LONG);
1769 }
1770
1771 $post_ids = (!empty($_POST['post_ids']) ) ? $_POST['post_ids'] : array();
1772 }
1773
1774 function save_bulkdatas() {
1775 $current_post_type = isset($_GET['post_type']) ? $_GET['post_type'] : 'post';
1776 if (in_array($current_post_type, $this->settings['posttypes'])) {
1777 $post_ids = (!empty($_POST['post_ids']) ) ? $_POST['post_ids'] : array();
1778 if (!empty($post_ids) && is_array($post_ids)) {
1779 foreach ($this->bulk_edit_fields as $sets) {
1780 foreach ($sets as $fieldname => $fieldlabel) {
1781 if ((false != $value = filter_input(INPUT_POST, $fieldname))) {
1782 foreach ($post_ids as $post_id) {
1783 update_post_meta($post_id, $fieldname, $value);
1784 }
1785 }
1786 }
1787 }
1788 }
1789 wp_send_json(true);
1790 exit;
1791 }
1792 wp_send_json(false);
1793 }
1794
1795 /**
1796 *
1797 * @param string $date
1798 * @param string $cat
1799 * @param boolean $display
1800 * @return boolean
1801 */
1802 public function display_caldate($date, $cat = '', $display = false, $colored=true, $thumbnail='', $title='',$tax_name='' ,$tax_term='') {
1803 $events = $this->get_events(array('nb' => -1, 'date' => $date, 'cat' => $cat, 'retreive' => true,'tax_name' => $tax_name ,'tax_term' => $tax_term));
1804 $nb = count($events);
1805 $ret = "";
1806 if(!$display && !$nb){
1807 $ret = date('j', $date);
1808 }
1809 if($nb){
1810 if ($display || $title) {
1811 $ret='<ul>';
1812 foreach ($events as $event) {
1813 if ($this->settings['emptylink'] == 0 && empty($event->post_content)) {
1814 $event->guid = '#';
1815 }
1816 $ret.='<li>'
1817 . '<a href="' . $event->permalink . '" title="'.esc_attr(sprintf(__('View event: %s', 'event-post'), $event->post_title)).'">'
1818 . '<h4>' . $event->post_title . '</h4>'
1819 .$this->get_single($event)
1820 . (!empty($thumbnail) ? '<span class="event_thumbnail_wrap">' . get_the_post_thumbnail($event->ID, $thumbnail) . '</span>' : '')
1821 .'</a>'
1822 . '</li>';
1823 }
1824 $ret.='</ul>';
1825 }
1826 if ($display) {
1827 // return $ret;
1828 }
1829 elseif($title) {
1830 $ret = '<span '.($colored?' style="color:#'.$events[0]->color.'"':'').'>'.date('j', $date).'</span>'.$ret;
1831 }
1832 else {
1833 $ret = '<button data-event="'. $tax_term .'" data-date="' . date('Y-m-d', $date).'"'
1834 .' class="'.apply_filters( 'event_post_class_calendar_link', 'eventpost_cal_link' ).'"'.($colored?' style="background-color:#'.$events[0]->color.'"':'')
1835 .' title="'.esc_attr(sprintf(_n('View %1$d event at date %2$s', 'View %1$d events at date %2$s', $nb, 'event-post'), $nb, $this->human_date($date, $this->settings['dateformat']))).'"'
1836 .'>'
1837 . date('j', $date)
1838 . '</button>';
1839 }
1840 }
1841
1842 return apply_filters('eventpost_display_caldate', $ret, $events, $date, $cat ,$display ,$colored ,$thumbnail ,$title ,$tax_name ,$tax_term );
1843 }
1844
1845
1846 /**
1847 * @param array $atts
1848 * @filter eventpost_params
1849 * @return string
1850 */
1851 public function calendar($atts) {
1852 extract(shortcode_atts(apply_filters('eventpost_params', array(
1853 'date' => date('Y-n'),
1854 'cat' => '',
1855 'mondayfirst' => 0, //1 : weeks starts on monday
1856 'datepicker' => 1,
1857 'colored' => 1,
1858 'display_title'=>0,
1859 'tax_name' => '',
1860 'tax_term' => '',
1861 'thumbnail'=>'',
1862 ), 'calendar'), $atts));
1863
1864 if($date && !preg_match('#[0-9][0-9][0-9][0-9]-[0-9][0-9]?#i', $date)){
1865 $date = date('Y-n', strtotime($date));
1866 }
1867 if(!$date){
1868 $date = date('Y-n');
1869 }
1870
1871 $annee = substr($date, 0, 4);
1872 $mois = substr($date, 5);
1873
1874 $time = mktime(0, 0, 0, $mois, 1, $annee);
1875
1876 $prev_year = strtotime('-1 Year', $time);
1877 $next_year = strtotime('+1 Year', $time);
1878 $prev_month = strtotime('-1 Month', $time);
1879 $next_month = strtotime('+1 Month', $time);
1880
1881 $JourMax = date("t", $time);
1882 $NoJour = -date("w", $time);
1883 if ($mondayfirst == 0) {
1884 $NoJour +=1;
1885 } else {
1886 $NoJour +=2;
1887 $this->Week[] = array_shift($this->Week);
1888 }
1889 if ($NoJour > 0 && $mondayfirst == 1) {
1890 $NoJour -=7;
1891 }
1892 $ret = '<table class="event-post-calendar-table">'
1893 . '<caption class="screen-reader-text">'
1894 . __('A calendar of events', 'event-post')
1895 . '</caption>';
1896 $ret.='<thead><tr><th colspan="7">';
1897 if ($datepicker == 1) {
1898 $ret.='<div class="eventpost-calendar-header">';
1899 $ret.='<span class="eventpost-cal-year"><button data-date="' . date('Y-n', $prev_year) . '" tabindex="0" title="'.sprintf(__('Switch to %s', 'event-post'), date('Y', $prev_year)).'" class="eventpost_cal_bt eventpost-cal-bt-prev">&laquo;</button><span class="eventpost-cal-header-text">';
1900 $ret.=$annee;
1901 $ret.='</span><button data-date="' . date('Y-n', $next_year) . '" title="'.sprintf(__('Switch to %s', 'event-post'), date('Y', $next_year)).'" class="eventpost_cal_bt eventpost-cal-bt-next">&raquo;</button></span>';
1902 $ret.='<span class="eventpost-cal-month"><button data-date="' . date('Y-n', $prev_month) . '" title="'.sprintf(__('Switch to %s', 'event-post'), date_i18n('F Y', $prev_month)).'" class="eventpost_cal_bt eventpost-cal-bt-prev">&laquo;</button><span class="eventpost-cal-header-text">';
1903 $ret.=$this->NomDuMois[abs($mois)];
1904 $ret.='</span><button data-date="' . date('Y-n', $next_month) . '" title="'.sprintf(__('Switch to %s', 'event-post'), date_i18n('F Y', $next_month)).'" class="eventpost_cal_bt eventpost-cal-bt-next">&raquo;</button> </span>';
1905 $ret.='<span class="eventpost-cal-today"><button data-date="' . date('Y-n') . '" class="eventpost_cal_bt">' . __('Today', 'event-post') . '</button></span>';
1906 $ret.='</div>';
1907 }
1908 $ret.='</th></tr><tr class="event_post_cal_days">';
1909 for ($w = 0; $w < 7; $w++) {
1910 $ret.='<th scope="col">' . strtoupper(substr($this->Week[$w], 0, 1)) . '</th>';
1911 }
1912 $ret.='</tr>';
1913 $ret.='</thead>';
1914
1915 $ret.='<tbody>';
1916 $sqldate = date('Y-m', $time);
1917 $cejour = date('Y-m-d');
1918 for ($semaine = 0; $semaine <= 5; $semaine++) { // 6 semaines par mois
1919 $tr_row_content ='';
1920 for ($journee = 0; $journee <= 6; $journee++) { // 7 jours par semaine
1921 if ($NoJour > 0 && $NoJour <= $JourMax) { // si le jour est valide a afficher
1922 $td = '<td class="event_post_day">';
1923 if ($sqldate . '-' . ($NoJour<10?'0':'').$NoJour == $cejour) {
1924 $td = '<td class="event_post_day_now">';
1925 }
1926 if ($sqldate . '-' . ($NoJour<10?'0':'').$NoJour < $cejour){
1927 $td = '<td class="event_post_day_over">'; // Patch ahf
1928 }
1929 $tr_row_content.=$td;
1930 $tr_row_content.= $this->display_caldate(mktime(0, 0, 0, $mois, $NoJour, $annee), $cat, false, $colored, $thumbnail, $display_title ,$tax_name ,$tax_term);
1931 $tr_row_content.='</td>';
1932 } else {
1933 $tr_row_content.='<td></td>';
1934 }
1935 $NoJour ++;
1936 }
1937 if($tr_row_content){
1938 $ret.='<tr>'.$tr_row_content.'</tr>';
1939 }
1940
1941 }
1942 $ret.='</tbody></table>';
1943 return $ret;
1944 }
1945
1946 public function ajaxlist(){
1947 echo $this->list_events(array(
1948 'nb' => esc_attr(FILTER_INPUT(INPUT_POST, 'nb')),
1949 'future' => esc_attr(FILTER_INPUT(INPUT_POST, 'future')),
1950 'past' => esc_attr(FILTER_INPUT(INPUT_POST, 'past')),
1951 'geo' => esc_attr(FILTER_INPUT(INPUT_POST, 'geo')),
1952 'width' => esc_attr(FILTER_INPUT(INPUT_POST, 'width')),
1953 'height' => esc_attr(FILTER_INPUT(INPUT_POST, 'height')),
1954 'zoom' => esc_attr(FILTER_INPUT(INPUT_POST, 'zoom')),
1955 'tile' => esc_attr(FILTER_INPUT(INPUT_POST, 'tile')),
1956 'title' => esc_attr(FILTER_INPUT(INPUT_POST, 'title')),
1957 'before_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'before_title')),
1958 'after_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'after_title')),
1959 'cat' => esc_attr(FILTER_INPUT(INPUT_POST, 'cat')),
1960 'tag' => esc_attr(FILTER_INPUT(INPUT_POST, 'tag')),
1961 'events' => esc_attr(FILTER_INPUT(INPUT_POST, 'events')),
1962 'style' => esc_attr(FILTER_INPUT(INPUT_POST, 'style')),
1963 'thumbnail' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail')),
1964 'thumbnail_size' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail_size')),
1965 'excerpt' => esc_attr(FILTER_INPUT(INPUT_POST, 'excerpt')),
1966 'orderby' => esc_attr(FILTER_INPUT(INPUT_POST, 'orderby')),
1967 'order' => esc_attr(FILTER_INPUT(INPUT_POST, 'order')),
1968 'class' => esc_attr(FILTER_INPUT(INPUT_POST, 'class')),
1969 'pages' => esc_attr(FILTER_INPUT(INPUT_POST, 'pages')),
1970 ), esc_attr(FILTER_INPUT(INPUT_POST, 'list_type')));
1971 exit;
1972 }
1973
1974 /**
1975 * echoes the content of the calendar in ajax context
1976 */
1977 public function ajaxcal() {
1978 $method = isset($_GET['action']) ? INPUT_GET : INPUT_POST;
1979 echo $this->calendar(array(
1980 'date' => esc_attr(FILTER_INPUT($method, 'date')),
1981 'cat' => esc_attr(FILTER_INPUT($method, 'cat')),
1982 'mondayfirst' => esc_attr(FILTER_INPUT($method, 'mf')),
1983 'datepicker' => esc_attr(FILTER_INPUT($method, 'dp')),
1984 'colored' => esc_attr(FILTER_INPUT($method, 'color')),
1985 'display_title' => esc_attr(FILTER_INPUT($method, 'display_title')),
1986 'thumbnail' => esc_attr(FILTER_INPUT($method, 'thumbnail')),
1987 'tax_name' => esc_attr(FILTER_INPUT($method, 'tax_name')),
1988 'tax_term' => esc_attr(FILTER_INPUT($method, 'tax_term')),
1989 ));
1990 exit();
1991 }
1992
1993 /**
1994 * echoes the date of the calendar in ajax context
1995 */
1996 public function ajaxdate() {
1997 echo $this->display_caldate(
1998 strtotime(esc_attr(FILTER_INPUT(INPUT_GET, 'date'))),
1999 esc_attr(FILTER_INPUT(INPUT_GET, 'cat')),
2000 true,
2001 esc_attr(FILTER_INPUT(INPUT_GET, 'color')),
2002 esc_attr(FILTER_INPUT(INPUT_GET, 'thumbnail')),
2003 esc_attr(FILTER_INPUT(INPUT_GET, 'display_title')),
2004 esc_attr(FILTER_INPUT(INPUT_GET, 'tax_name')),
2005 esc_attr(FILTER_INPUT(INPUT_GET, 'tax_term'))
2006 );
2007 exit();
2008 }
2009
2010 /**
2011 * echoes a date in ajax context
2012 */
2013 public function HumanDate() {
2014 if (isset($_REQUEST['date']) && !empty($_REQUEST['date'])) {
2015 $date = strtotime($_REQUEST['date']);
2016 echo $this->human_date($date, $this->settings['dateformat']).(date('H:i', $date)=='00:00' ? '' : ' '. date($this->settings['timeformat'], $date));
2017 exit();
2018 }
2019 }
2020
2021 /**
2022 * Displays a search form
2023 *
2024 * @param type $atts
2025 * @return type
2026 */
2027 public function search($atts) {
2028 $params = shortcode_atts(apply_filters('eventpost_params', array(
2029 'dates' => true,
2030 'q' => true,
2031 'tax' => false,
2032 ), 'search'), $atts);
2033 $this->list_id++;
2034
2035 $list_id = $this->list_id;
2036 $q = (false !== $q = filter_input(INPUT_GET, 'q')) ? $q : '';
2037 $from = (false !== $from = filter_input(INPUT_GET, 'from')) ? $from : '';
2038 $to = (false !== $to = filter_input(INPUT_GET, 'to')) ? $to : '';
2039 $tax = (false !== $tax = filter_input(INPUT_GET, 'tax')) ? $tax : '';
2040
2041 $cleaned_from = $this->date_cleanup($from);
2042 $cleaned_to = $this->date_cleanup($to);
2043 if(empty($cleaned_from)){
2044 $from=false;
2045 }
2046 if(empty($cleaned_to)){
2047 $to=false;
2048 }
2049
2050 // Search form
2051 $this->admin_scripts(null, true);
2052 wp_enqueue_style('jquery-ui', plugins_url('/css/jquery-ui.css', __FILE__), false, filemtime( "/$block_js" ));
2053 include (plugin_dir_path(__FILE__) . 'views/search-form.php');
2054
2055 // Results
2056 if ($list_id == filter_input(INPUT_GET, 'evenpost_search')) {
2057 $arg = array(
2058 'post_type' => $this->settings['posttypes'],
2059 'meta_key' => $this->META_START,
2060 'orderby' => 'meta_value',
2061 'order' => 'ASC',
2062 's' => $q
2063 );
2064 if ($tax) {
2065 $arg['cat'] = $tax;
2066 }
2067
2068 if ($from || $to) {
2069
2070 $arg['meta_query'] = array();
2071 if ($from) {
2072 $arg['meta_query'][] = array(
2073 'key' => $this->META_START,
2074 'value' => $from,
2075 'compare' => '>=',
2076 'type' => 'DATETIME'
2077 );
2078 }
2079 if ($to) {
2080 $arg['meta_query'][] = $meta_query = array(
2081 array(
2082 'key' => $this->META_END,
2083 'value' => $to,
2084 'compare' => '<=',
2085 'type' => 'DATETIME'
2086 ),
2087 );
2088 }
2089 }
2090 $events = new WP_Query($arg);
2091 include (plugin_dir_path(__FILE__) . 'views/search-results.php');
2092 wp_reset_query();
2093 }
2094 }
2095
2096 /**
2097 * AJAX Get lat long from address
2098 */
2099 public function GetLatLong() {
2100 if (isset($_REQUEST['q']) && !empty($_REQUEST['q'])) {
2101 // verifier le cache
2102 $q = $_REQUEST['q'];
2103 header('Content-Type: application/json');
2104 $transient_name = 'eventpost_osquery_' . $q;
2105 $val = get_transient($transient_name);
2106 if (false === $val || empty($val) || !is_string($val)) {
2107 $language = get_bloginfo('language');
2108 if (strpos($language, '-') > -1) {
2109 $language = strtolower(substr($language, 0, 2));
2110 }
2111 $remote_val = wp_safe_remote_request('http://nominatim.openstreetmap.org/search?q=' . urlencode($q) . '&format=json&accept-language=' . $language);
2112 if(json_decode($remote_val['body'])){
2113 $val = $remote_val['body'];
2114 }
2115 set_transient($transient_name, $val, 30 * DAY_IN_SECONDS);
2116 }
2117 echo $val;
2118 exit();
2119 }
2120 }
2121
2122 /**
2123 * alters columns
2124 * @param array $defaults
2125 * @return array
2126 * @filter eventpost_columns_head
2127 */
2128 public function columns_head($defaults) {
2129 $defaults['event'] = __('Event', 'event-post');
2130 $defaults['location'] = __('Location', 'event-post');
2131 return apply_filters('eventpost_columns_head', $defaults);
2132 }
2133
2134 /**
2135 * echoes content of a row in a given column
2136 * @param string $column_name
2137 * @param int $post_id
2138 * @action eventpost_columns_content
2139 */
2140 public function columns_content($column_name, $post_id) {
2141 if ($column_name == 'location') {
2142 $lat = get_post_meta($post_id, $this->META_LAT, true);
2143 $lon = get_post_meta($post_id, $this->META_LONG, true);
2144
2145 if (!empty($lat) && !empty($lon)) {
2146 add_thickbox();
2147 $color = get_post_meta($post_id, $this->META_COLOR, true);
2148 if ($color == ''){
2149 $color = '777777';
2150 }
2151 echo '<a href="https://www.openstreetmap.org/export/embed.html?bbox='.($lon-0.005).'%2C'.($lat-0.005).'%2C'.($lon+0.005).'%2C'.($lat+0.005).'&TB_iframe=true&width=600&height=550" class="thickbox" target="_blank">'
2152 . '<i class="dashicons dashicons-location" style="color:#'.$color.';"></i>'
2153 . '<span class="screen-reader-text">'.__('View on a map', 'event-post').'</span>'
2154 . get_post_meta($post_id, $this->META_ADD, true)
2155 . '</a> ';
2156 }
2157 $this->column_edit_hidden_fields($post_id, 'location');
2158 }
2159 if ($column_name == 'event') {
2160 echo $this->print_date($post_id, false);
2161 $this->column_edit_hidden_fields($post_id, 'event');
2162 }
2163 do_action('eventpost_columns_content', $column_name, $post_id);
2164 }
2165
2166 function column_edit_hidden_fields($post_id, $set){
2167 $event = $this->retreive($post_id);
2168 echo '<div class="hidden">';
2169 foreach($this->quick_edit_fields[$set] as $fieldname=>$fieldlabel){
2170 echo'<span class="inline-edit-value '.$fieldname.'">'.esc_attr($event->$fieldname).'</span>';
2171 }
2172 echo '</div>';
2173 }
2174
2175 /** ADMIN PAGES **/
2176
2177 /**
2178 * adds items to the native "right now" dashboard widget
2179 * @param array $elements
2180 * @return array
2181 */
2182 public function dashboard_right_now($elements){
2183 $nb_date = count($this->get_events(array('future'=>1, 'past'=>1, 'nb'=>-1)));
2184 $nb_geo = count($this->get_events(array('future'=>1, 'past'=>1, 'geo'=>1, 'nb'=>-1)));
2185 if($nb_date){
2186 array_push($elements, '<i class="dashicons dashicons-calendar"></i> <i href="edit.php?post_type=post">'.sprintf(__('%d Events','event-post'), $nb_date)."</i>");
2187 }
2188 if($nb_geo){
2189 array_push($elements, '<i class="dashicons dashicons-location"></i> <i href="edit.php?post_type=post">'.sprintf(__('%d Geolocalized events','event-post'), $nb_geo)."</i>");
2190 }
2191 return $elements;
2192 }
2193
2194 /*
2195 * feed
2196 * generate ICS or VCS files from a category
2197 */
2198
2199 /**
2200 *
2201 * @param timestamp $timestamp
2202 * @return string
2203 */
2204 public function ics_date($timestamp){
2205 return date("Ymd",$timestamp).'T'.date("His",$timestamp);
2206 }
2207
2208 public function get_gmt_offset(){
2209 $gmt_offset = get_option('gmt_offset ');
2210 $codegmt = 0;
2211 if ($gmt_offset != 0 && substr($gmt_offset, 0, 1) != '-' && substr($gmt_offset, 0, 1) != '+') {
2212 $codegmt = $gmt_offset * -1;
2213 $gmt_offset = '+' . $gmt_offset;
2214 }
2215 if(abs($gmt_offset < 10)){
2216 $gmt_offset = substr($gmt_offset, 0, 1).'0'.substr($gmt_offset, 1);
2217 }
2218 return $gmt_offset;
2219 }
2220
2221 private function generate_ics($event_id, $format){
2222 $export_file = plugin_dir_path(__FILE__).'inc/export/'.$format.'.php';
2223 if(is_numeric($event_id) && file_exists($export_file)){
2224 $event = $this->retreive($event_id);
2225 include $export_file;
2226 exit;
2227 }
2228 }
2229
2230 public function parse_request(){
2231 global $wp;
2232 if (preg_match('#^event-feed#i', $wp->request, $match)) {
2233 $this->feed();
2234 exit;
2235 }
2236 if (preg_match('#^eventpost/([0-9]*)\.(ics|vcs)#i', $wp->request, $match)) {
2237 $this->generate_ics($match[1], $match[2]);
2238 }
2239 }
2240
2241 public function export(){
2242 if(false !== $event_id=\filter_input(INPUT_GET, 'event_id',FILTER_SANITIZE_NUMBER_INT)){
2243 $format = \filter_input(INPUT_GET, 'format',FILTER_SANITIZE_STRING);
2244 $this->generate_ics($event_id, $format);
2245 }
2246 }
2247
2248
2249 /**
2250 * outputs an ICS document
2251 */
2252 public function feed(){
2253 if(false !== $cat=\filter_input(INPUT_GET, 'cat',FILTER_SANITIZE_STRING)){
2254 $vtz = get_option('timezone_string');
2255 $gmt = $this->get_gmt_offset();
2256 date_default_timezone_set($vtz);
2257 $separator = "\n";
2258
2259 header("content-type:text/calendar");
2260 header("Pragma: public");
2261 header("Expires: 0");
2262 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
2263 header("Cache-Control: public");
2264 header("Content-Disposition: attachment; filename=". str_replace('+','-',urlencode(get_option('blogname').'-'.$cat)).".ics;" );
2265
2266 $props = array();
2267
2268 // General
2269 $props[] = 'BEGIN:VCALENDAR';
2270 $props[] = 'PRODID://WordPress//Event-Post-V'. file_get_contents(('VERSION')).'//EN';
2271 $props[] = 'VERSION:2.0';
2272
2273 // Timezone
2274 if(!empty($vtz)){
2275 array_push($props,
2276 'BEGIN:VTIMEZONE',
2277 'TZID:'.$vtz,
2278 'BEGIN:DAYLIGHT',
2279 'TZOFFSETFROM:+0100',
2280 'TZOFFSETTO:'.($gmt).'00',
2281 'DTSTART:19700329T020000',
2282 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3',
2283 'END:DAYLIGHT',
2284 'BEGIN:STANDARD',
2285 'TZOFFSETFROM:'.($gmt).'00',
2286 'TZOFFSETTO:+0100',
2287 'TZNAME:CET',
2288 'DTSTART:19701025T030000',
2289 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10',
2290 'END:STANDARD',
2291 'END:VTIMEZONE'
2292 );
2293 }
2294
2295 // Events
2296 $events=$this->get_events(array('cat'=>$cat,'nb'=>-1));
2297 foreach ($events as $event) {
2298 if($event->time_start && $event->time_end){
2299 array_push($props,
2300 'BEGIN:VEVENT',
2301 'CREATED:'.$this->ics_date(strtotime($event->post_date)).'Z',
2302 'LAST-MODIFIED:'.$this->ics_date(strtotime($event->post_modified)).'Z',
2303 'SUMMARY:'.$event->post_title,
2304 'UID:'.md5(site_url()."_eventpost_".$event->ID),
2305 'LOCATION:'.str_replace(',','\,',$event->address),
2306 'DTSTAMP:'.$this->ics_date($event->time_start).(!empty($vtz)?'':'Z'),
2307 'DTSTART'.(!empty($vtz)?';TZID='.$vtz:'').':'.$this->ics_date($event->time_start).(!empty($vtz)?'':'Z'),
2308 'DTEND'.(!empty($vtz)?';TZID='.$vtz:'').':'.$this->ics_date($event->time_end).(!empty($vtz)?'':'Z'),
2309 'DESCRIPTION:'.trim(chunk_split($event->post_excerpt."\\n\\n".$event->permalink, 60, "\n")),
2310 'END:VEVENT'
2311 );
2312 }
2313 }
2314
2315 // End
2316 $props[] = 'END:VCALENDAR';
2317
2318 echo implode($separator, $props);
2319 exit;
2320 }
2321 }
2322 }
2323