PluginProbe
Event Post / 5.12.0
Event Post v5.12.0
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.12.0, at eventpost.php

3,313 lines 102.4 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&mtm_source=plugin-uri
5 * Description: Add calendar and/or geolocation metadata on any posts.
6 * Version: 5.12.0
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&mtm_source=author
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 * @package event-post
16 */
17 global $EventPost;
18 $EventPost = new EventPost();
19
20 $EventPost_cache=array();
21
22 function EventPost(){
23 global $EventPost;
24 return $EventPost;
25 }
26 function event_post_format_color($color){
27 return str_replace('#', '', $color);
28 }
29 function event_post_get_all_terms($post_id){
30 $taxonomies= get_taxonomies('','names');
31
32 return wp_get_post_terms($post_id, $taxonomies);
33 }
34
35
36 /**
37 * The main class where everything begins.
38 *
39 * Add calendar and/or geolocation metadata on posts
40 */
41 class EventPost {
42 /**
43 * The current version
44 *
45 * @var array
46 */
47 public $version = '5.9.2';
48
49 // --------------------------------------------------------------------------------
50 // Post metas
51
52 /**
53 * The meta name for event start date
54 *
55 * @var string
56 */
57 public $META_START = 'event_begin';
58
59 /**
60 * The meta name for event end date
61 *
62 * @var string
63 */
64 public $META_END = 'event_end';
65
66 /**
67 * The meta name for event color
68 *
69 * @var string
70 */
71 public $META_COLOR = 'event_color';
72
73 /**
74 * The meta name for event icon
75 *
76 * @var string
77 */
78 public $META_ICON = 'event_icon';
79
80 // --------------------------------------------------------------------------------
81 // Post metas related to location
82
83 /**
84 * The meta name for event address
85 *
86 * @var string
87 */
88 public $META_ADD = 'geo_address';
89
90 /**
91 * The meta name for event latitude
92 *
93 * @var string
94 *
95 * @see http://codex.wordpress.org/Geodata
96 */
97 public $META_LAT = 'geo_latitude';
98
99 /**
100 * The meta name for event longitude
101 *
102 * @var string
103 *
104 * @see http://codex.wordpress.org/Geodata
105 */
106 public $META_LONG = 'geo_longitude';
107
108 /**
109 * The meta name for event location
110 *
111 * @var string
112 *
113 * @see https://schema.org/location
114 */
115 public $META_VIRTUAL_LOCATION = 'event_virtual_location';
116
117 // --------------------------------------------------------------------------------
118 // Post metas related to status
119
120 /**
121 * The meta name for event status
122 *
123 * @var string
124 *
125 * @see https://schema.org/eventStatus
126 */
127 public $META_STATUS = 'event_status';
128
129 /**
130 * The meta name for event attendance mode
131 *
132 * @var string
133 *
134 * @see https://schema.org/eventAttendanceMode
135 */
136 public $META_ATTENDANCE_MODE = 'event_attendance_mode';
137
138 /**
139 * The meta name for event organizer
140 *
141 * @var string
142 *
143 * @see https://schema.org/Organization
144 */
145 public $META_ORGANIZATION = 'event_organization';
146
147 /**
148 * The meta name for event organizer
149 *
150 * @var string
151 * @see https://schema.org/Offer
152 */
153 public $META_OFFER = 'event_offer';
154
155 // --------------------------------------------------------------------------------
156 // Usefull variables
157
158 /**
159 * ID of the current list
160 *
161 * @var int
162 */
163 public $list_id;
164
165 /**
166 * ID of the current map
167 *
168 * @var int
169 */
170 public $map_id=0;
171
172 /**
173 * Schema as been outputed or not
174 *
175 * @var bool
176 */
177 private $is_schema_output=false;
178
179 /**
180 * Month names
181 *
182 * @var array
183 */
184 public $NomDuMois;
185
186 /**
187 * Week days
188 *
189 * @var array
190 */
191 public $Week;
192
193 /**
194 * Currencies
195 *
196 * @var array
197 */
198 public $currencies = array();
199
200 /**
201 * Date format
202 *
203 * @var string
204 */
205 public $dateformat;
206
207 /**
208 * Pagination
209 *
210 * @var array
211 */
212 private $pagination;
213
214 /**
215 * Plugin path
216 *
217 * @var string
218 */
219 public $plugin_path;
220
221 /**
222 * Script suffix
223 *
224 * @var string
225 */
226 private $script_sufix;
227
228 /**
229 * Settings values
230 *
231 * @var array
232 */
233 public $settings;
234
235 // --------------------------------------------------------------------------------
236 // Option values
237
238 /**
239 * Map interractions (from openlayers)
240 *
241 * @var array
242 */
243 public $map_interactions;
244
245 /**
246 * Fields supported by quick-edit
247 *
248 * @var array
249 */
250 public $quick_edit_fields;
251
252 /**
253 * Fields supported by bulk-edit
254 *
255 * @var array
256 */
257 public $bulk_edit_fields;
258
259 /**
260 * Supported attendance modes
261 *
262 * @var array
263 */
264 public $attendance_modes;
265
266 /**
267 * Supported statuses
268 *
269 * @var array
270 */
271 public $statuses;
272
273 /**
274 * Default list schema (HTML template)
275 *
276 * @var string
277 */
278 public $default_list_shema;
279
280 /**
281 * Default timeline schema (HTML template)
282 *
283 * @var string
284 */
285 public $default_timeline_shema;
286
287 /**
288 * Current list schema (HTML template)
289 *
290 * @var string
291 */
292 public $list_shema;
293
294 /**
295 * Current timeline schema (HTML template)
296 *
297 * @var string
298 */
299 public $timeline_shema;
300
301 // Map variables
302 /**
303 * Map tiles
304 *
305 * @var array
306 */
307 public $maps;
308
309 /**
310 * Dirpath for map tiles
311 *
312 * @var string
313 */
314 public $markpath;
315
316 /**
317 * Base URL for map tiles
318 *
319 * @var string
320 */
321 public $markurl;
322
323 // --------------------------------------------------------------------------------
324 // Classes
325
326 /**
327 * Taxonomies object
328 *
329 * @var \EventPost\Taxonomies
330 */
331 public $Taxonomies;
332
333 /**
334 * Icons object
335 *
336 * @var \EventPost\Icons
337 */
338 public $DashIcons;
339
340 /**
341 * Settings object
342 *
343 * @var \EventPost\Settings
344 */
345 public $Settings;
346
347 /**
348 * Shortcodes object
349 *
350 * @var \EventPost\Shortcodes
351 */
352 public $Shortcodes;
353
354 /**
355 * Allowed tags in main outputs
356 *
357 * @var array
358 */
359 public $kses_tags;
360
361
362 public function __construct() {
363 add_action('init', array(&$this,'init'), 1);
364 add_action('init', array(&$this,'widgets_init'), 10);
365 add_action('init', array(&$this, 'register_widgets'), 30, 1);
366
367 add_action('save_post', array(&$this, 'save_postdata'));
368 add_filter('dashboard_glance_items', array(&$this, 'dashboard_right_now'));
369
370 // Scripts
371 add_action( 'admin_init', array(&$this, 'editor_styles'));
372 add_action('admin_enqueue_scripts', array(&$this, 'admin_head'));
373 add_action('admin_print_scripts', array(&$this, 'admin_scripts'));
374 add_action('admin_print_scripts', array(&$this, 'load_scripts'), 1);
375 add_action('wp_enqueue_scripts', array(&$this, 'load_scripts'), 1);
376 add_action('wp_enqueue_scripts', array(&$this, 'load_styles'));
377
378 // Single
379 add_filter('the_content', array(&$this, 'display_single'), 9999);
380 add_filter('the_title', array(&$this, 'the_title'), 9999, 2);
381 add_action('the_event', array(&$this, 'print_single'));
382 add_action('wp_head', array(&$this, 'single_header'));
383 add_action('wpseo_schema_webpage', array(&$this, 'wpseo_schema_webpage'));
384
385 // Ajax
386 add_action('wp_ajax_EventPostGetLatLong', array(&$this, 'GetLatLong'));
387 add_action('wp_ajax_EventPostHumanDate', array(&$this, 'HumanDate'));
388 add_action('wp_ajax_EventPostList', array(&$this, 'ajaxlist'));
389 add_action('wp_ajax_EventPostTimeline', array(&$this, 'ajaxTimeline'));
390 add_action('wp_ajax_EventPostNextPage', array(&$this, 'ajaxGetNextPage'));
391 add_action('wp_ajax_nopriv_EventPostNextPage', array(&$this, 'ajaxGetNextPage'));
392 add_action('wp_ajax_EventPostMap', array(&$this, 'ajaxmap'));
393 add_action('wp_ajax_EventPostCalendar', array(&$this, 'ajaxcal'));
394 add_action('wp_ajax_nopriv_EventPostCalendar', array(&$this, 'ajaxcal'));
395 add_action('wp_ajax_EventPostCalendarDate', array(&$this, 'ajaxdate'));
396 add_action('wp_ajax_nopriv_EventPostCalendarDate', array(&$this, 'ajaxdate'));
397
398 // Calendar publishing
399 add_action('parse_request', array(&$this, 'parse_request'), 100);
400 add_action('wp_ajax_EventPostExport', array(&$this, 'export'));
401 add_action('wp_ajax_nopriv_EventPostExport', array(&$this, 'export'));
402 add_action('wp_ajax_EventPostFeed', array(&$this, 'feed'));
403 add_action('wp_ajax_nopriv_EventPostFeed', array(&$this, 'feed'));
404
405 // Internal filters
406 add_filter('eventpost_list_shema',array(&$this, 'custom_shema'),10,1);
407
408 // Quick edit
409 add_action( 'bulk_edit_custom_box', array( &$this, 'bulk_edit' ), 10, 2 );
410 add_action( 'quick_edit_custom_box', array( &$this, 'quick_edit' ), 10, 2 );
411 add_action( 'admin_print_scripts-edit.php', array(&$this, 'scripts_edit') );
412 add_action( 'wp_ajax_inline-save', array(&$this, 'inline_save'), 1 );
413 add_action( 'bulk_edit_posts', array(&$this, 'save_bulkdatas'), 10, 2 );
414 add_filter( 'eventpost_inline_field', array(&$this, 'inline_field_color'), 10, 3);
415 add_filter( 'eventpost_inline_field', array(&$this, 'inline_field_icon'), 10, 3);
416
417 $inc_path = plugin_dir_path(__FILE__).'inc/';
418 $this->plugin_path = plugin_dir_path(__FILE__);
419 include_once ($inc_path . 'class-settings.php');
420 include_once ($inc_path . 'wrappers.php');
421 include_once ($inc_path . 'deprecated/widget.php');
422 include_once ($inc_path . 'deprecated/widget.cal.php');
423 include_once ($inc_path . 'deprecated/widget.map.php');
424 include_once ($inc_path . 'class-multisite.php');
425 include_once ($inc_path . 'class-shortcodes.php');
426 include_once ($inc_path . 'openweathermap.php');
427 include_once ($inc_path . 'class-children.php');
428 include_once ($inc_path . 'class-icons.php');
429 include_once ($inc_path . 'class-taxonomies.php');
430
431 $this->DashIcons = new EventPost\Icons();
432 $this->Settings = new EventPost\Settings($this->DashIcons);
433 $this->Taxonomies = new EventPost\Taxonomies($this->DashIcons);
434 }
435
436 /**
437 * PHP4 constructor
438 */
439 public function EventPost(){
440 $this->__construct();
441 }
442
443 public function init(){
444 $admin_url = admin_url('admin-ajax.php?action=EventPostFeed');
445 $admin_url = str_replace(site_url(), '', $admin_url);
446 $plugins_url = plugins_url('export/ics.php', __FILE__);
447 $plugins_url = str_replace(site_url(), '', $plugins_url);
448 add_rewrite_rule('event-feed/?', $admin_url , 'top');
449 add_rewrite_rule('eventpost/([0-9]*)\.(ics|vcs)?',$plugins_url, 'top');
450
451 $this->list_id = 0;
452 $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'));
453 $this->Week = array(__('Sunday', 'event-post'), __('Monday', 'event-post'), __('Tuesday', 'event-post'), __('Wednesday', 'event-post'), __('Thursday', 'event-post'), __('Friday', 'event-post'), __('Saturday', 'event-post'));
454 $this->attendance_modes = array(
455 'OfflineEventAttendanceMode' => _x('Physical', 'Attendance Mode', 'event-post'),
456 'MixedEventAttendanceMode' => _x('Mixed', 'Attendance Mode', 'event-post'),
457 'OnlineEventAttendanceMode' => _x('Online', 'Attendance Mode', 'event-post'),
458 );
459 $this->statuses = array(
460 'EventScheduled' => _x('Scheduled', 'Event Status', 'event-post'),
461 'EventCancelled' => _x('Cancelled', 'Event Status', 'event-post'),
462 'EventMovedOnline' => _x('Moved Online', 'Event Status', 'event-post'),
463 'EventPostponed' => _x('Postoned', 'Event Status', 'event-post'),
464 'EventRescheduled' => _x('Rescheduled', 'Event Status', 'event-post'),
465 'EventCompleted' => _x('Completed', 'Event Status', 'event-post'),
466 );
467
468 $this->maps = $this->get_maps();
469 $this->settings = $this->get_settings();
470
471 do_action('evenpost_init', $this);
472
473 // Edit
474 add_action('add_meta_boxes', array(&$this, 'add_custom_box'));
475 foreach($this->settings['posttypes'] as $posttype){
476 add_filter('manage_'.$posttype.'_posts_columns', array(&$this, 'columns_head'), 2);
477 add_action('manage_'.$posttype.'_posts_custom_column', array(&$this, 'columns_content'), 10, 2);
478 }
479 $this->Taxonomies->add_fields_to_taxonomies($this->settings['posttypes']);
480
481 $this->markpath = '';
482 $this->markurl = '';
483 if (!empty($this->settings['markpath']) && !empty($this->settings['markurl'])) {
484 $this->markpath = ABSPATH.'/'.$this->settings['markpath'];
485 $this->markurl = $this->settings['markurl'];
486 } else {
487 // $this->markpath = plugin_dir_path(__FILE__) . 'markers/';
488 // $this->markurl = plugins_url('/markers/', __FILE__);
489 }
490
491 $this->currencies = include (plugin_dir_path(__FILE__) . 'inc/data/currencies.php');
492
493 $this->dateformat = str_replace(array('yy', 'mm', 'dd'), array('Y', 'm', 'd'), __('yy-mm-dd', 'event-post'));
494
495 $this->default_list_shema = apply_filters('eventpost_default_list_shema', array(
496 'container' => '<%type% class="event_loop %id% %class%" id="%listid%" style="%style%" %attributes%>'.
497 '%list%'.
498 '%pagination%'.
499 '</%type%><!-- .event_loop -->',
500 'item' => '<%child% class="event_item %class%" data-color="%color%" style="%style%">'.
501 '<a href="%event_link%">'.
502 '%event_thumbnail%'.
503 '<h5>%event_title% </h5>'.
504 '</a>'.
505 '%event_price%'.
506 '%event_date%'.
507 '%event_cat%'.
508 '%event_location%'.
509 '%event_excerpt%'.
510 '</%child%><!-- .event_item -->'
511 ));
512 $this->list_shema = apply_filters('eventpost_list_shema',$this->default_list_shema);
513
514 $this->default_timeline_shema = apply_filters('eventpost_default_timeline_shema', array(
515 'container' => '
516 <%type% class="event_loop %id% %class%" id="%listid%" style="%style%" %attributes%>
517 %prev_arrow%
518 <div class="track">
519 %list%
520 </div>
521 %next_arrow%
522 </%type%><!-- .event_loop -->',
523 'item' => '<%child% class="event_item %class%" data-color="%color%" style="%style%">
524 <div class="anchor" style="background-color:#%color%"></div>
525 %event_date%
526 %event_location%
527 %event_cat%
528 %event_excerpt%
529 <a href="%event_link%">
530 %event_thumbnail%
531 <h5>%event_title%</h5>
532 </a>
533 %event_price%
534 </%child%><!-- .event_item -->'
535 ));
536 $this->timeline_shema = apply_filters('eventpost_timeline_shema',$this->default_timeline_shema);
537
538 $this->map_interactions=array(
539 'DragRotate'=>__('Drag Rotate', 'event-post'),
540 'DoubleClickZoom'=>__('Double Click Zoom', 'event-post'),
541 'DragPan'=>__('Drag Pan', 'event-post'),
542 'PinchRotate'=>__('Pinch Rotate', 'event-post'),
543 'PinchZoom'=>__('Pinch Zoom', 'event-post'),
544 'KeyboardPan'=>__('Keyboard Pan', 'event-post'),
545 'KeyboardZoom'=>__('Keyboard Zoom', 'event-post'),
546 'MouseWheelZoom'=>__('Mouse Wheel Zoom', 'event-post'),
547 'DragZoom'=>__('Drag Zoom', 'event-post'),
548 );
549
550 $this->quick_edit_fields = apply_filters('eventpost_quick_edit_fields', array(
551 'event'=>array(
552 $this->META_START=>__('Begin:', 'event-post'),
553 $this->META_END=>__('End:', 'event-post'),
554 $this->META_COLOR=>__('Color:', 'event-post'),
555 $this->META_ICON=>__('Icon:', 'event-post'),
556 ),
557 'location'=>array(
558 $this->META_ADD=>__('Address:', 'event-post'),
559 $this->META_LAT=>__('Latitude:', 'event-post'),
560 $this->META_LONG=>__('Longitude:', 'event-post'),
561 ),
562 )
563 );
564 $this->bulk_edit_fields = apply_filters('eventpost_bulk_edit_fields', array(
565 'event'=>array(
566 $this->META_COLOR=>__('Color:', 'event-post'),
567 $this->META_ICON=>__('Icon:', 'event-post'),
568 ),
569 )
570 );
571
572 $this->kses_tags = apply_filters('eventpost_kses_tags', json_decode(
573 file_get_contents(plugin_dir_path(__FILE__).'inc/data/kses-tags.json'),
574 true
575 ));
576
577
578 }
579
580 /**
581 * Init all variables when WP is ready
582 *
583 * @action evenpost_init
584 * @filter eventpost_default_list_shema
585 * @filter eventpost_list_shema
586 */
587 public function widgets_init(){
588 $this->Shortcodes = new EventPost\Shortcodes();
589
590 if(function_exists('register_block_type')){
591 $block_path = plugin_dir_path(__FILE__).'inc/blocks/';
592 include_once ($block_path . 'eventslist.php');
593 include_once ($block_path . 'eventstimeline.php');
594 include_once ($block_path . 'eventsmap.php');
595 include_once ($block_path . 'eventscalendar.php');
596 include_once ($block_path . 'eventdetails.php');
597 }
598
599
600 // WooCommerce
601 if (class_exists('WooCommerce') && in_array('product', $this->settings['posttypes'])) {
602 include_once (plugin_dir_path(__FILE__).'inc/woocommerce.php');
603 }
604 }
605
606 public function register_widgets(){
607 register_widget('EventPost_List');
608 register_widget('EventPost_Map');
609 register_widget('EventPost_Cal');
610 }
611
612 /**
613 * Usefull hexadecimal to decimal converter. Returns an array of RGB from a given hexadecimal color.
614 *
615 * @param string $color
616 *
617 * @return array $color($R, $G, $B)
618 */
619 public function hex2dec($color = '000000') {
620 $tbl_color = array();
621 if(!is_string($color) || empty($color)){
622 $color = '000000';
623 }
624 if (substr($color, 0, 1)!='#'){
625 $color = '#' . $color;
626 }
627 $tbl_color['R'] = hexdec(substr($color, 1, 2));
628 $tbl_color['G'] = hexdec(substr($color, 3, 2));
629 $tbl_color['B'] = hexdec(substr($color, 5, 2));
630 return $tbl_color;
631 }
632
633 /**
634 * Fetch all registered image sizes
635 *
636 * @global array $_wp_additional_image_sizes
637 *
638 * @return array
639 */
640 function get_thumbnail_sizes(){
641 global $_wp_additional_image_sizes;
642 $sizes = array('thumbnail', 'medium', 'large', 'full');
643 foreach(array_keys($_wp_additional_image_sizes) as $size){
644 $sizes[]=$size;
645 }
646 return $sizes;
647 }
648
649 /**
650 * Get blog settings, load and saves default settings if needed. Can be filterred using
651 *
652 * @example `<?php add_filter('eventpost_getsettings', 'some_function'); ?>`
653 *
654 * @action eventpost_getsettings_action
655 * @filter eventpost_getsettings
656 *
657 * @return array
658 */
659 public function get_settings() {
660 $ep_settings = $this->Settings->get_settings();
661 return apply_filters('eventpost_getsettings', $ep_settings);
662 }
663
664 /**
665 * Checks if HTML schemas are not empty
666 *
667 * @param array $shema
668 *
669 * @return array
670 */
671 public function custom_shema($shema){
672 if(!empty($this->settings['container_shema'])){
673 $shema['container']=$this->settings['container_shema'];
674 }
675 if(!empty($this->settings['item_shema'])){
676 $shema['item']=$this->settings['item_shema'];
677 }
678 return $shema;
679 }
680
681 /**
682 * Parse the maps.json file. Custom maps can be added by using the `eventpost_getsettings` filter like the following example:
683 *
684 * ```
685 * <?php
686 * add_filter('eventpost_getsettings', 'map_function');
687 * function map_function($maps){
688 * array_push($maps, array(
689 * 'name'=>'Myt custom map',
690 * 'id'=>'custom_map',
691 * 'urls'=>array(
692 * 'http://a.customurl.org/{z}/{x}/{y}.png',
693 * 'http://b.customurl.org/{z}/{x}/{y}.png',
694 * 'http://c.customurl.org/{z}/{x}/{y}.png',
695 * )
696 * ));
697 * return $maps;
698 * }
699 * ?>
700 * ```
701 *
702 * @filter eventpost_maps
703 *
704 * @return array of map arrays ['name', 'id', 'urls']
705 */
706 public function get_maps() {
707 $maps = array();
708 $filename = plugin_dir_path(__FILE__) . 'maps.json';
709 if (is_file($filename) && (false !== $json = json_decode(file_get_contents($filename)))) {
710 // Convert objects to array to ensure retrocompatibility
711 $arrays = array();
712 foreach($json as $map){
713 $arrays[$map->id] = (array) $map;
714 }
715 $maps = apply_filters('eventpost_maps', $arrays);
716 }
717 return $maps;
718 }
719
720 /**
721 * Get colors
722 *
723 * @return array
724 */
725 public function get_colors() {
726 $colors = array();
727 if (is_dir($this->markpath)) {
728 $files = scandir($this->markpath);
729 foreach ($files as $file) {
730 if (substr($file, -4) == '.png') {
731 $colors[substr($file, 0, -4)] = $this->markurl . $file;
732 }
733 }
734 }
735 return $colors;
736 }
737
738 /**
739 * Get color of a post
740 *
741 * @param int $post_id
742 * @param bool $default
743 * @param bool $check_taxo
744 *
745 * @return string color
746 */
747 public function get_post_color($post_id, $default = false, $check_taxo = false) {
748 $color = get_post_meta($post_id, $this->META_COLOR,true);
749 if($color && !empty($color)){
750 return event_post_format_color($color);
751 }else{
752 if($check_taxo){
753 foreach(event_post_get_all_terms($post_id) as $term){
754 $taxo_color = $this->Taxonomies->get_taxonomy_color($term->term_id);
755 if($taxo_color){
756 return event_post_format_color($taxo_color);
757 }
758 }
759 }
760 }
761 return event_post_format_color($default);
762 }
763
764 /**
765 * Get icon of a post
766 *
767 * @param int $post_id
768 * @param bool $default
769 * @param bool $check_taxo
770 *
771 * @return string|false icon
772 */
773 public function get_post_icon($post_id, $default = false, $check_taxo = false) {
774 $icon = get_post_meta($post_id, $this->META_ICON,true);
775 if($icon && !empty($icon)){
776 return $icon;
777 }else{
778 if($check_taxo){
779 foreach(event_post_get_all_terms($post_id) as $term){
780 $taxo_icon = $this->Taxonomies->get_taxonomy_icon($term->term_id);
781 if($taxo_icon){
782 return event_post_format_color($taxo_icon);
783 }
784 }
785 }
786 }
787 return $default;
788 }
789
790 /**
791 * Get the URL of a marker
792 *
793 * @param string $color
794 *
795 * @return sring
796 */
797 public function get_marker($color) {
798 if (is_file($this->markpath . $color . '.png')) {
799 return $this->markurl . $color . '.png';
800 }
801 return "";
802 }
803
804 /**
805 * Enqueue CSS files
806 */
807 public function load_styles($deps = null) {
808 //CSS
809 if(!empty($this->settings['customcss'])){
810 wp_enqueue_style('event-post-custom', $this->settings['customcss']);
811 }
812 elseif(is_file(get_stylesheet_directory().'/event-post.css') || is_file(get_template_directory().'/event-post.css')){
813 wp_enqueue_style('event-post-custom', get_theme_file_uri('event-post.css'));
814 }
815 else{
816 wp_register_style('event-post', plugins_url('/build/front/front.css', __FILE__), $deps, filemtime( "{$this->plugin_path}/build/front/front.css" ));
817 wp_enqueue_style('event-post');
818 }
819
820 // Lib scripts
821 wp_enqueue_style('dashicons', includes_url('/css/dashicons.min.css'));
822 }
823
824 /**
825 * Enqueue Editor style
826 */
827 public function editor_styles() {
828 add_editor_style( plugins_url('/build/front/front.css', __FILE__) );
829 }
830
831 /**
832 * Enqueue JS files
833 */
834 public function load_scripts() {
835 wp_enqueue_script('event-post', plugins_url('/build/front/front.js', __FILE__), array(), filemtime( "{$this->plugin_path}/build/front/front.js" ), true);
836 $maps = $this->maps;
837 foreach($maps as $m=>$map){
838 if(isset($map['api_param']) && $this->settings['tile_api_key']){
839 foreach($map['urls'] as $i=>$url){
840 $maps[$m]['urls'][$i] = add_query_arg($map['api_param'], $this->settings['tile_api_key'], $url);
841 }
842 }
843 }
844 wp_add_inline_script('event-post', 'var EventPost = EventPost || {}; EventPost.front='.wp_json_encode(array(
845 'scripts' => array(
846 'map' => plugins_url('/build/map/event-map.js', __FILE__)
847 ),
848 'imgpath' => plugins_url('/img/', __FILE__),
849 'maptiles' => $maps,
850 'defaulttile' => $this->settings['tile'],
851 'zoom' => $this->settings['zoom'],
852 'ajaxurl' => admin_url() . 'admin-ajax.php',
853 'map_interactions'=>$this->map_interactions,
854 )), 'before');
855 }
856 /**
857 * Enqueue JS files for maps
858 */
859 public function load_map_scripts() {
860 $this->load_styles(array('event-post-map'));
861 // JS
862 if(is_admin()){
863 $this->admin_scripts(array('jquery', 'event-post-map'));
864 }
865 }
866
867 /**
868 * Enqueue CSS files in admin
869 */
870 public function admin_head() {
871 $page = basename($_SERVER['SCRIPT_NAME']);
872 if( $page!='post-new.php' && $page!='edit-tags.php' && !($page=='post.php' && filter_input(INPUT_GET, 'action')=='edit') && !($page=='options-general.php' && filter_input(INPUT_GET, 'page')=='event-settings') ){
873 return;
874 }
875 wp_enqueue_style('event-post-admin', plugins_url('/build/admin/admin.css', __FILE__), false, filemtime( "{$this->plugin_path}/build/admin/admin.css" ));
876 }
877
878 /**
879 * Enqueue JS files in admin
880 */
881 public function admin_scripts($deps = array('jquery'), $force=false) {
882 $page = basename($_SERVER['SCRIPT_NAME']);
883 if(!$force &&
884 $page!='post-new.php' &&
885 $page!='edit-tags.php' &&
886 $page!='term.php' &&
887 !($page=='post.php' && filter_input(INPUT_GET, 'action')=='edit') &&
888 !($page=='options-general.php' && filter_input(INPUT_GET, 'page')=='event-settings')
889 ){
890 return;
891 }
892 wp_enqueue_script('jquery');
893 wp_enqueue_script('jquery-effects-core');
894 wp_enqueue_script('jquery-effects-shake');
895 wp_enqueue_style( 'wp-color-picker');
896 wp_enqueue_script( 'wp-color-picker');
897 if(!is_array($deps)){
898 $deps = array('jquery','wp-color-picker');
899 }
900 if($this->settings['datepicker']=='simple' || !is_admin() || (isset($_GET['page']) && $_GET['page']=='event-settings')){
901 wp_enqueue_script('jquery-ui-datepicker');
902 $deps[] = 'jquery-ui-datepicker';
903 }
904 wp_enqueue_script('event-post-admin', plugins_url('/build/admin/admin.js', __FILE__), $deps, filemtime( "{$this->plugin_path}/build/admin/admin.js" ), true);
905 $language = get_bloginfo('language');
906 if (strpos($language, '-') > -1) {
907 $language = strtolower(substr($language, 0, 2));
908 }
909 wp_add_inline_script('event-post-admin', 'var EventPost = EventPost || {}; EventPost.admin='.wp_json_encode(array(
910 'ajaxurl' => admin_url('admin-ajax.php'),
911 'imgpath' => plugins_url('/img/', __FILE__),
912 'date_choose' => __('Choose', 'event-post'),
913 'date_format' => __('yy-mm-dd', 'event-post'),
914 'more_icons' => __('More icons', 'event-post'),
915 'pick_a_date'=>__('Pick a date','event-post'),
916 'use_current_location'=>__('Use my current location','event-post'),
917 'start_drag'=>__('Click to<br>drag the map<br>and change location','event-post'),
918 'empty_address'=>__('Be kind to fill a non empty address:)', 'event-post'),
919 'search'=>__('Type an address', 'event-post'),
920 'search_button'=>__('Search', 'event-post'),
921 'geocoding_attribution'=>__('Geocoding by <a href="https://nominatim.openstreetmap.org/" target="_blank">OpenStreetmap Nominatim</a>', 'event-post'),
922 'stop_drag'=>_x('Done','Stop allowing to drag the map', 'event-post'),
923 'datepickeri18n'=>array(
924 // Translators: %1$s is the month name, %2$s is the day number, %3$s is the year, %4$s is the hour, %5$s is the minute
925 'order'=>__( '%1$s %2$s, %3$s @ %4$s:%5$s', 'event-post'),
926 'day'=>__('Day', 'event-post'),
927 'month'=>__('Month', 'event-post'),
928 'year'=>__('Day', 'event-post'),
929 'hour'=>__('Hour', 'event-post'),
930 'minute'=>__('Minute', 'event-post'),
931 'ok'=>__('OK', 'event-post'),
932 'cancel'=>__('Cancel', 'event-post'),
933 'remove'=>__('Remove', 'event-post'),
934 'edit'=>__('Edit', 'event-post'),
935 'months'=>$this->NomDuMois,
936 ),
937 'META_START' => $this->META_START,
938 'META_END' => $this->META_END,
939 'META_ADD' => $this->META_ADD,
940 'META_LAT' => $this->META_LAT,
941 'META_LONG' => $this->META_LONG,
942 'META_STATUS' => $this->META_STATUS,
943 'META_ATTENDANCE_MODE' => $this->META_ATTENDANCE_MODE,
944 'lang'=>$language,
945 'maptiles' => $this->maps,
946 'defaulttile' => $this->settings['tile'],
947 'palette' => $this->get_theme_palette("hex"),
948 'available_images' => $this->get_colors(),
949 )));
950 }
951 function scripts_edit() {
952 // load only when editing a supported post type
953 $current_post_type = isset($_GET['post_type']) ? $_GET['post_type'] : 'post';
954 if ( in_array( $current_post_type, $this->settings['posttypes'] ) ) {
955 wp_enqueue_script( 'eventpost-inline-edit', plugins_url( 'build/admin/inline-edit.js', __FILE__ ), array( 'jquery', 'inline-edit-post' ), '', true );
956 wp_add_inline_script('eventpost-inline-edit', 'var EventPost = EventPost || {}; EventPost.inlineEdit='.wp_json_encode(array(
957 'quick'=>$this->quick_edit_fields,
958 'bulk'=>$this->bulk_edit_fields,
959 )));
960 }
961 }
962
963 function get_rich_result($event){
964 /*
965 * https://search.google.com/test/rich-results
966 {
967 "@context": "https://schema.org",
968 "@type": "Event",
969 "name": "The Adventures of Kira and Morrison",
970 "startDate": "2025-07-21T19:00",
971 "endDate": "2025-07-21T23:00",
972 "eventStatus": "https://schema.org/EventScheduled",
973 "eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
974 "location": {
975 "@type": "VirtualLocation",
976 "url": "https://operaonline.stream5.com/"
977 },
978 "image": [
979 "https://example.com/photos/1x1/photo.jpg",
980 "https://example.com/photos/4x3/photo.jpg",
981 "https://example.com/photos/16x9/photo.jpg"
982 ],
983 "description": "The Adventures of Kira and Morrison is coming to Snickertown in a can’t miss performance.",
984 "offers": {
985 "@type": "Offer",
986 "url": "https://www.example.com/event_offer/12345_201803180430",
987 "price": "30",
988 "priceCurrency": "USD",
989 "availability": "https://schema.org/InStock",
990 "validFrom": "2024-05-21T12:00"
991 },
992 "performer": {
993 "@type": "PerformingGroup",
994 "name": "Kira and Morrison"
995 }
996 }
997 */
998 $location_virtual = array(
999 '@type'=>'VirtualLocation',
1000 'url'=>$event->virtual_location,
1001 );
1002 $physical_location = array(
1003 '@type'=>'place',
1004 'name'=>$event->address,
1005 'address'=>$event->address,
1006 'geo'=>array(
1007 '@type'=>'GeoCoordinates',
1008 'latitude'=>$event->lat,
1009 'longitude'=>$event->long,
1010 ),
1011 );
1012 $min = 60 * get_option('gmt_offset');
1013 $sign = $min < 0 ? "-" : "+";
1014 $absmin = abs($min);
1015 $gmt_offset = sprintf("%s%02d:%02d", $sign, $absmin/60, $absmin%60);
1016 $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';
1017
1018 $rich_data = array(
1019 '@context'=>'https://schema.org',
1020 '@type'=>'event',
1021 'name'=>$event->post_title,
1022 'datePublished'=>str_replace(' ', 'T', $event->post_date_gmt).$gmt_offset,
1023 'dateModified'=>str_replace(' ', 'T', $event->post_modified_gmt).$gmt_offset,
1024 'startDate'=>$event->time_start ? date($time_format, $event->time_start) : null,
1025 'endDate'=>$event->time_end ? date($time_format, $event->time_end) : null,
1026 'eventStatus'=>$event->status,
1027 'eventAttendanceMode'=>$event->attendance_mode,
1028 'location'=> ($event->attendance_mode == 'MixedEventAttendanceMode') ? array($location_virtual,$physical_location) : ($event->attendance_mode == 'OnlineEventAttendanceMode' ? $location_virtual : $physical_location),
1029 'image'=> has_post_thumbnail($event->ID) ? array(
1030 get_the_post_thumbnail_url($event->ID, 'post-thumbnail'),
1031 get_the_post_thumbnail_url($event->ID, 'medium'),
1032 get_the_post_thumbnail_url($event->ID, 'large'),
1033 get_the_post_thumbnail_url($event->ID, 'full'),
1034 ) : null,
1035 'description'=>$event->description,
1036 );
1037 if(!empty($event->organization)){
1038 $rich_data['organizer'] = array(
1039 '@type'=>'Organization',
1040 'name'=>$event->organization,
1041 );
1042 }
1043 if(!empty($event->offer)){
1044 $rich_data['offers'] = array(
1045 '@type'=>'Offer',
1046 // 'availability'=>$event->availability,
1047 // 'validFrom'=>date($time_format, $event->time_start),
1048 );
1049 if(!empty($event->offer['url'])){
1050 $rich_data['offers']['url'] = $event->offer['url'];
1051 }
1052 if(!empty($event->offer['price'])){
1053 $rich_data['offers']['price'] = $event->offer['price'];
1054 }
1055 if(!empty($event->offer['currency'])){
1056 $rich_data['offers']['priceCurrency'] = $event->offer['currency'];
1057 }
1058 }
1059
1060 return apply_filters('event-post-rich-result', $rich_data, $event);
1061 }
1062
1063 function wpseo_schema_webpage($rich_result){
1064 $event = $this->retreive();
1065 if ($event != false){
1066 if ($event->time_start != '' && $event->time_end != '') {
1067 $rich_result = array_merge($rich_result, $this->get_rich_result($event));
1068 }
1069 $this->is_schema_output = true;
1070 }
1071 return $rich_result;
1072 }
1073
1074 function get_theme_palette($return = "hex"){
1075 $theme_options = wp_get_global_settings();
1076 $colors = [];
1077 if(isset($theme_options['color']['palette']['theme'])){
1078 $colors = $theme_options['color']['palette']['theme'];
1079 }elseif(isset($theme_options['color']['palette']['default'])){
1080 $colors = $theme_options['color']['palette']['default'];
1081 }
1082 if($return == "hex"){
1083 $color_hexs = [];
1084 foreach($colors as $color){
1085 $color_hexs[] = $color["color"];
1086 }
1087 return $color_hexs;
1088 }
1089 return $colors;
1090 }
1091
1092 /**
1093 * Add custom header meta for single events
1094 */
1095 public function single_header() {
1096 if (is_single()) {
1097 $twitter_label_id=0;
1098 $event = $this->retreive();
1099 $has_location = $has_time = false;
1100 if ($event != false) {
1101 if ($event->address != '' || ($event->lat != '' && $event->long != '')) {
1102 $twitter_label_id++;
1103 $has_location = true;
1104 ?>
1105 <meta name="geo.placename" content="<?php echo esc_attr($event->address) ?>" />
1106 <meta name="geo.position" content="<?php echo esc_attr($event->lat) ?>;<?php echo esc_attr($event->long) ?>" />
1107 <meta name="ICBM" content="<?php echo esc_attr($event->lat) ?>;<?php echo esc_attr($event->long) ?>" />
1108 <meta property="place:location:latitude" content="<?php echo esc_attr($event->lat) ?>" />
1109 <meta property="place:location:longitude" content="<?php echo esc_attr($event->long) ?>" />
1110 <meta name="twitter:label<?php echo esc_attr($twitter_label_id); ?>" content="<?php esc_attr_e('Location', 'event-post'); ?>"/>
1111 <meta name="twitter:data<?php echo esc_attr($twitter_label_id); ?>" content="<?php echo esc_attr($event->address) ?>"/>
1112 <?php
1113 }
1114 if ($event->start != '' && $event->end != '') {
1115 $has_time = true;
1116 $twitter_label_id++;
1117 ?>
1118 <meta name="datetime-coverage-start" content="<?php echo esc_attr(date('c', $event->time_start)) ?>" />
1119 <meta name="datetime-coverage-end" content="<?php echo esc_attr(date('c', $event->time_end)) ?>" />
1120 <meta name="twitter:label<?php echo esc_attr($twitter_label_id); ?>" content="<?php echo esc_attr('Date', 'event-post'); ?>"/>
1121 <meta name="twitter:data<?php echo esc_attr($twitter_label_id); ?>" content="<?php echo esc_attr($this->human_date($event->time_start)) ?>"/>
1122 <?php
1123 }
1124 if(($has_location || $has_time) && !$this->is_schema_output){
1125 $rich_result = $this->get_rich_result($event);
1126 $this->is_schema_output = true;
1127 ?>
1128 <script type="application/ld+json"><?php echo \wp_json_encode($rich_result); ?></script>
1129 <?php
1130 }
1131 }
1132 }
1133 }
1134
1135 /**
1136 * Cleanups a date
1137 *
1138 * @param type $str
1139 *
1140 * @since 5.0.1
1141 *
1142 * @return string
1143 */
1144 public function date_cleanup($str){
1145 return trim(str_replace(array('0', ' ', ':', '-'), '', $str));
1146 }
1147
1148 /**
1149 * Checks if a date is valid or not
1150 *
1151 * @param string $str
1152 *
1153 * @return boolean
1154 */
1155 public function dateisvalid($str) {
1156 return is_string($str) && $this->date_cleanup($str) != '';
1157 }
1158
1159 /**
1160 * Parse a date from a string
1161 *
1162 * @param string $date
1163 * @param string $sep
1164 *
1165 * @return string
1166 */
1167 public function parsedate($date, $sep = '') {
1168 if (!empty($date)) {
1169 return substr($date, 0, 10) . $sep . substr($date, 11, 8);
1170 } else {
1171 return '';
1172 }
1173 }
1174
1175 /**
1176 * Sanitize a coordinate string
1177 * Only keeps, numbers, dots and commas
1178 *
1179 * @param string $str
1180 *
1181 * @since 5.9.9
1182 *
1183 * @return string
1184 */
1185 public function sanitize_coordinate($str){
1186 return preg_replace('/[^0-9\.,-]/', '', $str);
1187 }
1188
1189 /**
1190 * Format a date for humans
1191 *
1192 * @param mixed $date
1193 * @param string $format
1194 *
1195 * @return type
1196 */
1197 public function human_date($date, $format = 'l j F Y') {
1198 if($this->settings['dateforhumans']){
1199 if (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y')) {
1200 return __('today', 'event-post');
1201 } elseif (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y', strtotime('+1 day'))) {
1202 return __('tomorrow', 'event-post');
1203 } elseif (is_numeric($date) && date('d/m/Y', $date) == date('d/m/Y', strtotime('-1 day'))) {
1204 return __('yesterday', 'event-post');
1205 }
1206 }
1207 return date_i18n($format, $date);
1208 }
1209
1210 /**
1211 * Returns a range of dates
1212 *
1213 * @param timestamp $time_start
1214 * @param timestamp $time_end
1215 *
1216 * @return string
1217 */
1218 public function delta_date($time_start, $time_end){
1219 if(!$time_start || !$time_end){
1220 return;
1221 }
1222
1223 // Translators: %1$s, %4$s are opening tags, %2$s and %5$s are closing tag, %3$s is the first date, %6$s is the second date
1224 $from_to_days = _x('%1$sfrom%2$s %3$s %4$sto%5$s %6$s', 'Days', 'event-post');
1225 // Translators: %1$s is the first date, %4$s is the second date, %2$s is an opening tag, %3$s is a closing tag
1226 $single_day_at = _x('%1$s%2$s,%3$s %4$s', 'From/To single day at time', 'event-post');
1227 // Translators: %1$s, %4$s are opening tags, %2$s and %5$s are closing tag, %3$s is the first hour, %6$s is the second hour
1228 $from_to_hours = _x('%1$sfrom%2$s %3$s %4$sto%5$s %6$s', 'Hours', 'event-post');
1229 // Translators: %1$s is an opening tag, %2$s is a closing tag, %3$s is the time
1230 $at_time = _x('%1$sat%2$s %3$s', 'Time', 'event-post');
1231
1232 //Display dates
1233 $dates="\t\t\t\t".'<div class="event_date" data-start="' . $this->human_date($time_start) . '" data-end="' . $this->human_date($time_end) . '">';
1234 // Same day
1235 if (date('Ymd', $time_start) == date('Ymd', $time_end)) {
1236 $dates.= "\n\t\t\t\t\t\t\t".'<time itemprop="dtstart" datetime="' . date_i18n('c', $time_start) . '">'
1237 . '<span class="date date-single">' . $this->human_date($time_end, $this->settings['dateformat']) . "</span>";
1238 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') {
1239 $dates.= ' '.sprintf(
1240 $from_to_hours,
1241 '<span class="linking_word linking_word-from">',
1242 '</span>',
1243 '<span class="time time-start">' . date_i18n($this->settings['timeformat'], $time_start) . '</span>',
1244 '<span class="linking_word linking_word-to">',
1245 '</span>',
1246 '<span class="time time-end">' . date_i18n($this->settings['timeformat'], $time_end) . '</span>'
1247 );
1248 }
1249 elseif (date('H:i', $time_start) != '00:00') {
1250 $dates.= ' '.sprintf(
1251 $at_time,
1252 '<span class="linking_word">',
1253 '</span>',
1254 '<span class="time time-single">' . date_i18n($this->settings['timeformat'], $time_start) . '</span>'
1255 );
1256 }
1257 $dates.="\n\t\t\t\t\t\t\t".'</time>';
1258 }
1259 // Not same day
1260 else {
1261 $dates.= ' '.sprintf(
1262 $from_to_days,
1263 '<span class="linking_word linking_word-from">',
1264 '</span>',
1265 '<time class="date date-start" itemprop="dtstart" datetime="' . date('c', $time_start) . '">'
1266 . ((date('H:i:s', $time_start) != '00:00:00' || date('H:i:s', $time_end) != '00:00:00')
1267 ? 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>')
1268 : $this->human_date($time_start, $this->settings['dateformat'])
1269 )
1270 . '</time>',
1271 '<span class="linking_word linking_word-to">',
1272 '</span>',
1273 '<time class="date date-to" itemprop="dtend" datetime="' . date('c', $time_end) . '">'
1274 . ((date('H:i:s', $time_start) != '00:00:00' || date('H:i:s', $time_end) != '00:00:00')
1275 ? 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>')
1276 : $this->human_date($time_end, $this->settings['dateformat'])
1277 )
1278 . '</time>'
1279 );
1280 }
1281 $dates.="\n\t\t\t\t\t\t".'</div><!-- .event_date -->';
1282 return $dates;
1283 }
1284
1285 /**
1286 * Displays a date
1287 *
1288 * @param WP_Post object $post
1289 * @param mixed $links
1290 *
1291 * @return string
1292 */
1293 public function print_date($post = null, $links = 'deprecated', $context='') {
1294 $dates = '';
1295 $event = $this->retreive($post);
1296 if ($event != false){
1297 if ($event->start != '' && $event->end != '') {
1298
1299 $dates.=$this->delta_date($event->time_start, $event->time_end);
1300 if( // Status setting
1301 $this->settings['displaystatus'] == 'both' ||
1302 ($this->settings['displaystatus'] == 'single' && is_single() ) ||
1303 ($this->settings['displaystatus'] == 'list' && !is_single() )
1304 ){
1305 $dates.='<span class="eventpost-status">'.$this->statuses[$event->status].'</span>';
1306 }
1307 $timezone_string = get_option('timezone_string');
1308 $gmt_offset = $gmt = $this->get_gmt_offset();
1309
1310 if (
1311 !is_admin()
1312 && ( // Export when setting
1313 $this->settings['export_when'] == 'both' ||
1314 ( $this->settings['export_when'] == 'future' && $this->is_future($event) ) ||
1315 ( $this->settings['export_when'] == 'past' && $this->is_past($event) )
1316 )
1317 && ( // Export setting
1318 $this->settings['export'] == 'both' ||
1319 ($this->settings['export'] == 'single' && is_single() ) ||
1320 ($this->settings['export'] == 'list' && !is_single() )
1321 )
1322 ) {
1323 // Export event
1324 $title = urlencode($post->post_title);
1325 $address = urlencode($post->address);
1326 $desc = urlencode($event->description."\n\n".$post->permalink);
1327 $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');
1328 $d_s = date("Ymd", $event->time_start) . ($allday ? '' : 'T' . date("His", $event->time_start));
1329 $d_e = date("Ymd", $event->time_end) . ($allday ? '' : 'T' . date("His", $event->time_end));
1330 $uid = $post->ID . '-' . $post->blog_id;
1331 $url = $event->permalink;
1332
1333 // format de date ICS
1334 $permalink_structure = get_option( 'permalink_structure' );
1335 if($permalink_structure != ""){
1336 $ics_url = site_url('eventpost/'.$event->ID.'.ics');
1337 $vcs_url = site_url('eventpost/'.$event->ID.'.vcs');
1338 }
1339 else{
1340 $ics_url = add_query_arg(array('action'=>'EventPostExport', 'event_id'=>$event->ID, 'format'=>'ics'), admin_url('admin-ajax.php'));
1341 $vcs_url = add_query_arg(array('action'=>'EventPostExport', 'event_id'=>$event->ID, 'format'=>'vcs'), admin_url('admin-ajax.php'));
1342
1343 }
1344
1345 // format de date Google cal
1346 //$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';
1347 $google_url = add_query_arg(array(
1348 'action'=>'TEMPLATE',
1349 'trp'=>'false',
1350 'sprop'=>'name',
1351 'text'=>$title,
1352 'dates'=>$d_s.'/'.$d_e.'', // Removed Z to fix TZ issue
1353 'location'=>$address,
1354 'details'=>$desc,
1355 'gmt'=> urlencode($gmt_offset)
1356 ), 'https://www.google.com/calendar/event');
1357 if(!empty($timezone_string)){
1358 $google_url = add_query_arg(array(
1359 'ctz'=>$timezone_string,
1360 ), $google_url);
1361 }
1362
1363 $dates.='
1364 <span class="eventpost-date-export">
1365 <a href="' . $ics_url . '" class="event_link event-export ics" target="_blank" title="' . __('Download ICS file', 'event-post') . '">ical</a>
1366 <a href="' . $google_url . '" class="event_link event-export gcal" target="_blank" title="' . __('Add to Google calendar', 'event-post') . '">Google</a>
1367 <a href="' . $vcs_url . '" class="event_link event-export vcs" target="_blank" title="' . __('Add to Outlook', 'event-post') . '">outlook</a>
1368 <i class="dashicons-before dashicons-calendar"></i>
1369 </span>';
1370 }
1371 }
1372 }
1373 return apply_filters('eventpost_printdate', $dates);
1374 }
1375
1376 /**
1377 * Outputs location of an event
1378 *
1379 * @param WP_Post object $post
1380 *
1381 * @return string
1382 */
1383 public function print_location($post=null, $context='') {
1384 $location = '';
1385 if ($post == null)
1386 $post = get_post();
1387 elseif (is_numeric($post)) {
1388 $post = get_post($post);
1389 }
1390 if (!isset($post->start)) {
1391 $post = $this->retreive($post);
1392 }
1393 if ($post != false){
1394 $this->map_id++;
1395 $address = $post->address;
1396 $lat = $post->lat;
1397 $long = $post->long;
1398 $color = $this->get_post_color($post->ID, $this->settings['default_color'], true);
1399 $icon = $this->DashIcons->icons[$this->get_post_icon($post->ID, $this->settings['default_icon'], true)];
1400 $virtual_location = $post->virtual_location;
1401 $attendance_mode = $post->attendance_mode;
1402
1403 if ($this->is_online($post) && $virtual_location) {
1404 $location.="\t\t\t\t".'<div><a href="'.esc_url($virtual_location).'" class="eventpost-virtual-location-link" target="_blank" rel="noopener">'
1405 .__('Join link', 'event-post')
1406 .'</a></div>'
1407 ."\n";
1408 }
1409 if ($this->is_offline($post) && ($address != '' || ($lat != '' && $long != ''))) {
1410 $location.="\t\t\t\t".'<address';
1411 if ($lat != '' && $long != '') {
1412 $geo_attributes = ' data-latitude="' . esc_attr($lat) . '"
1413 data-longitude="' . esc_attr($long) . '"
1414 data-marker="' . esc_attr($this->get_marker($color)) . '"
1415 data-iconcode="' .esc_attr($icon). '"
1416 data-icon="' . esc_attr(mb_convert_encoding('&#x'.$icon.';', 'UTF-8', 'HTML-ENTITIES')). '"
1417 data-color="#' . esc_attr($color). '"
1418 data-id="' . $post->ID . '-'.$this->map_id.'"';
1419 $location.=' '.$geo_attributes;
1420 }
1421 $location.=' itemprop="adr" class="eventpost-address">'
1422 . "\n\t\t\t\t\t\t\t".'<span>'
1423 . "\n".$address
1424 . "\n\t\t\t\t\t\t\t". '</span>';
1425 if ($context=='single' && $lat != '' && $long != '') {
1426 $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=' . esc_attr($lat) .'&amp;lon=' . esc_attr($long) . '&amp;zoom=13" target="_blank" itemprop="geo" ' . $geo_attributes . '>' . __('Map', 'event-post') . '</a>';
1427 }
1428 $location.="\n\t\t\t\t\t\t".'</address>';
1429 if (wp_is_mobile() && $lat != '' && $long != '') {
1430 $location.="\n\t\t\t\t\t\t".'<a class="event_link gps-geo-link" href="geo:' . esc_attr($lat) . ',' . esc_attr($long) . '" target="_blank" itemprop="geo" ' . $geo_attributes . '><i class="dashicons-before dashicons-location"></i> ' . __('Open in app', 'event-post') . '</a>';
1431 }
1432 }
1433 }
1434 return apply_filters('eventpost_printlocation', $location);
1435 }
1436
1437 /**
1438 * Compute darkness of the color
1439 *
1440 * @param string $color
1441 *
1442 * @return float
1443 */
1444 public function color_darkness($color){
1445 $color = str_replace('#', '', $color);
1446 $rgb = array();
1447 for ($x=0;$x<3;$x++) {
1448 $rgb[$x] = hexdec(substr($color,(2*$x),2));
1449 }
1450 return (max($rgb) + min($rgb)) / 510;
1451 }
1452
1453 /**
1454 * Outputs categories of an event
1455 *
1456 * @param WP_Post object $post
1457 *
1458 * @return string
1459 */
1460 public function print_categories($post=null, $context='') {
1461 if ($post == null)
1462 $post = get_post();
1463 elseif (is_numeric($post)) {
1464 $post = get_post($post);
1465 }
1466 if (!isset($post->start)) {
1467 $post = $this->retreive($post);
1468 }
1469 $cats = '';
1470 if ($post != false){
1471 $categories = $post->Taxonomies;
1472 if ($categories) {
1473 $cats.="\t\t\t\t".'<span class="event_categories">';
1474
1475 foreach ($categories as $category) {
1476 $cats.="\t\t\t\t\t".'<span ';
1477 $classes = array('event-term', 'event_term_category');
1478 $darkness = 0;
1479 $color = $this->Taxonomies->get_taxonomy_color($category->term_id);
1480 if ($color != '' && $color) {
1481 $cats.=' style="background-color:#' . $color . '"';
1482
1483 $darkness = $this->color_darkness($color);
1484 if($darkness < 0.5){
1485 array_push($classes, 'event-post-bg-dark');
1486 }
1487 else{
1488 array_push($classes, 'event-post-bg-light');
1489 }
1490
1491 }
1492 $cats.=' class="'.implode(' ', $classes).'">';
1493 $cats .= $category->name . ' ';
1494 $cats.='</span>';
1495 }
1496 $cats.='</span>';
1497 }
1498 }
1499 return $cats;
1500 }
1501
1502 /**
1503 * Generate, return or output date event datas
1504 *
1505 * @param WP_Post object $post
1506 * @param string $class
1507 *
1508 * @filter eventpost_get_single
1509 *
1510 * @return string
1511 */
1512 public function get_single($post = null, $class = '', $context='') {
1513 if ($post == null) {
1514 $post = $this->retreive();
1515 }
1516 if ($post != null){
1517 $datas_date = $this->print_date($post, null, $context);
1518 $datas_cat = $this->print_categories($post, $context);
1519 $datas_loc = $this->print_location($post, $context);
1520 $classes = array(
1521 'event_data',
1522 'status-'.$post->status,
1523 'location-type-'.$post->attendance_mode,
1524 $class
1525 );
1526 if ($datas_date != '' || $datas_loc != '') {
1527 $rgb = $this->hex2dec($post->color);
1528 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">'
1529 . apply_filters('eventpost_get_single', $datas_date . $datas_cat . $datas_loc, $post)
1530 . '</div>';
1531 }
1532 }
1533 return '';
1534 }
1535
1536 /**
1537 * Displays dates of a gieven post
1538 *
1539 * @param WP_Post object $post
1540 * @param string $class
1541 *
1542 * @return string
1543 */
1544 public function get_singledate($post = null, $class = '', $context='') {
1545 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 -->';
1546 }
1547
1548 /**
1549 * Displays coloured terms of a given post
1550 *
1551 * @param WP_Post object $post
1552 * @param string $class
1553 *
1554 * @return string
1555 */
1556 public function get_singlecat($post = null, $class = '', $context='') {
1557 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 -->';
1558 }
1559
1560 /**
1561 * Displays location of a given post
1562 *
1563 * @param WP_Post object $post
1564 * @param string $class
1565 *
1566 * @return string
1567 */
1568 public function get_singleloc($post = null, $class = '', $context='') {
1569 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 -->';
1570 }
1571
1572 /**
1573 * Uses `the_content` filter to add event details before or after the content of the current post
1574 *
1575 * @param string $content
1576 *
1577 * @return string
1578 */
1579 public function display_single($content) {
1580 if (is_page() || !is_single() || is_home() || !in_the_loop() || !is_main_query()){
1581 return $content;
1582 }
1583
1584 $post = $this->retreive();
1585 if($post != false){
1586 // If the post is a product, don't display the event bar, use product tab instead
1587 if($post->post_type=='product'){
1588 return $content;
1589 }
1590
1591 $eventbar = apply_filters('eventpost_contentbar', $this->get_single($post, 'event_single', 'single'), $post);
1592 if($this->settings['singlepos']=='before'){
1593 $content=$eventbar.$content;
1594 }
1595 elseif($this->settings['singlepos']=='after'){
1596 $content.=$eventbar;
1597 }
1598 $this->load_map_scripts();
1599 }
1600 return $content;
1601 }
1602
1603 /**
1604 * Outputs events details (dates, geoloc, terms) of given post
1605 *
1606 * @param WP_Post object $post
1607 *
1608 * @return void
1609 */
1610 public function print_single($post = null) {
1611 echo wp_kses_post($this->get_single($post));
1612 }
1613
1614 /**
1615 * Alter the post title in order to add icons if needed
1616 *
1617 * @param string $title
1618 *
1619 * @return string
1620 */
1621 public function the_title($title, $post_id = null){
1622 if(!$post_id || !in_the_loop() || !$this->settings['loopicons']){
1623 return $title;
1624 }
1625 $icons_ = array(
1626 // Emojis
1627 1=>array('🗓', '🗺'),
1628 // Dashicons
1629 2=>array('<span class="dashicons dashicons-calendar"></span>', '<span class="dashicons dashicons-location"></span>'),
1630 );
1631
1632 $event = $this->retreive($post_id);
1633 if ($event !== false){
1634 if(!empty($event->start)){
1635 $title .= ' '.$icons_[$this->settings['loopicons']][0];
1636 }
1637 if(!empty($event->lat) && !empty($event->long)){
1638 $title .= ' '.$icons_[$this->settings['loopicons']][1];
1639 }
1640 }
1641 return $title;
1642 }
1643
1644
1645 function get_price($event,$html=false){
1646 $price = '';
1647 $text_price = $price;
1648 if($event->post_type == 'product'){
1649 $product_id = $event->ID;
1650 $product = wc_get_product($product_id);
1651 $price = $product->get_price();
1652 $currency = get_woocommerce_currency_symbol();
1653 if($product->get_sale_price() != ""){
1654 $old_price = $product->get_regular_price();
1655 $text_price = '<span class="event_price"><del>'.$old_price . $currency . '</del> '.$price. $currency. '</span>';
1656 } else {
1657 $text_price = '<span class="event_price"> '.$price . $currency.'</span>';
1658 }
1659 }
1660 if ($html == true) {
1661 return $text_price;
1662 } else {
1663 return $price;
1664 }
1665 }
1666
1667 /**
1668 * Return an HTML list of events
1669 *
1670 * @param array $atts
1671 * @param string $id
1672 * @param string $context
1673 *
1674 * @filter eventpost_params($defaults, 'list_events')
1675 * @filter eventpost_listevents
1676 * @filter eventpost_item_scheme_entities
1677 * @filter eventpost_item_scheme_values
1678 *
1679 * @return string
1680 */
1681 public function list_events($atts, $id = 'event_list', $context='') {
1682 $ep_settings = $this->settings;
1683 $defaults = array(
1684 'nb' => 0,
1685 'type' => 'div',
1686 'future' => true,
1687 'past' => false,
1688 'geo' => 0,
1689 'width' => '',
1690 'height' => '',
1691 'list' => 0,
1692 'zoom' => '',
1693 'map_position' => 'false',
1694 'latitude' => '',
1695 'longitude' => '',
1696 'tile' => $ep_settings['tile'],
1697 'pop_element_schema' => 'false',
1698 'htmlPop_element_schema' => '',
1699 'title' => '',
1700 'before_title' => '<h3>',
1701 'after_title' => '</h3>',
1702 'cat' => '',
1703 'tag' => '',
1704 'tax_name' => '',
1705 'tax_term' => '',
1706 'events' => '',
1707 'style' => '',
1708 'thumbnail' => '',
1709 'thumbnail_size' => '',
1710 'excerpt' => '',
1711 'orderby' => 'meta_value',
1712 'order' => 'ASC',
1713 'class' => '',
1714 'className' => '',
1715 'container_schema' => $this->list_shema['container'],
1716 'item_schema' => $this->list_shema['item'],
1717 'pages' => false,
1718 'paged' => '',
1719 );
1720 // Map UI options
1721 foreach($this->map_interactions as $int_key=>$int_name){
1722 $defaults[$int_key]=true;
1723 }
1724 $atts_old_nb = $defaults['nb'];
1725 if($id == "event_timeline"){
1726 $atts_old_nb = $atts['nb'];
1727 $atts['nb'] = 0;
1728 }
1729
1730 $atts = shortcode_atts(apply_filters('eventpost_params', $defaults, 'list_events'), $atts);
1731
1732 extract($atts);
1733 if (!is_array($events)) {
1734 $events = $this->get_events($atts);
1735 }
1736
1737 $ret = '';
1738 $this->list_id++;
1739 if (sizeof($events) > 0) {
1740 if (!empty($title)) {
1741 $ret .= esc_html($before_title) . esc_html($title) . esc_html($after_title);
1742 }
1743
1744 $type = in_array($type, ['div', 'ul', 'ol']) ? $type : 'div';
1745 $child = in_array($type, ['ul', 'ol']) ? 'li' : 'div';
1746
1747 $html = '';
1748
1749 if($id=='event_geolist'){
1750 $this->load_map_scripts();
1751 $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);
1752 }
1753 $attributes = '';
1754 $prev_arrow = "";
1755 $next_arrow = "";
1756 $item_child_style = "";
1757 if($id == "event_timeline"){
1758 $prev_arrow = '<div class="previous"><span class="screen-reader-text">'.__('« Previous Events', 'event-post')."</span></div>";
1759 $next_arrow = '<div class="next"><span class="screen-reader-text">'.__('Next Events »', 'event-post')."</span></div>";
1760 if($atts_old_nb != 0){
1761 $item_child_style = 'width : '.((100/$atts_old_nb) - 2).'%;';
1762 }
1763 $attributes .= ' data-nb="'.$atts_old_nb.'" data-filter="'.http_build_query($atts).'" ';
1764 }
1765
1766 foreach ($events as $event) {
1767 $text_price = $this->get_price($event,true);
1768 $class_item = array(
1769 $this->is_future($event) ? 'event_future' : 'event_past',
1770 'status-'.$event->status,
1771 'location-type-'.$event->attendance_mode,
1772 );
1773 $taxonomies= get_taxonomies('','names');
1774 $post_terms = [];
1775 $terms = wp_get_post_terms($event->ID, $taxonomies);
1776 foreach($terms as $term){
1777 $class_item[] = $term->taxonomy.'-'.$term->name;
1778 }
1779 if ($ep_settings['emptylink'] == 0 && empty($event->post_content)) {
1780 $event->permalink = '#' . $id . $this->list_id;
1781 }
1782 elseif(empty($event->permalink)){
1783 $event->permalink=$event->guid;
1784 }
1785 $html.=str_replace(
1786 apply_filters('eventpost_item_scheme_entities', array(
1787 '%child%',
1788 '%class%',
1789 '%color%',
1790 '%event_link%',
1791 '%event_thumbnail%',
1792 '%event_title%',
1793 '%event_price%',
1794 '%event_date%',
1795 '%event_cat%',
1796 '%event_location%',
1797 '%event_excerpt%',
1798 '%style%',
1799 )), apply_filters('eventpost_item_scheme_values', array(
1800 $child,
1801 implode(' ', $class_item),
1802 $this->get_post_color($event->ID, $this->settings['default_color'],true),
1803 $event->permalink,
1804 $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>' : '',
1805 $event->post_title,
1806 $event->post_type == 'product' ? $text_price : '',
1807 $this->get_singledate($event, '', $context),
1808 $this->get_singlecat($event, '', $context),
1809 $this->get_singleloc($event, '', $context),
1810 $excerpt == true && $event->description!='' ? '<span class="event_exerpt">'.$event->description.'</span>' : '',
1811 $item_child_style,
1812 ), $event), $item_schema
1813 );
1814
1815 }
1816 if($id == 'event_geolist'){
1817 if($height==''){
1818 $height = '300px';
1819 }
1820 if($width==''){
1821 $width = '100%';
1822 }
1823 $attributes .= ' data-tile="'.esc_attr($tile).'"
1824 data-width="'.esc_attr($width).'"
1825 data-height="'.esc_attr($height).'"
1826 data-zoom="'.esc_attr($zoom).'"
1827 data-map_position="'.esc_attr($map_position).'"
1828 data-latitude="'.esc_attr($latitude).'"
1829 data-longitude="'.esc_attr($longitude).'"
1830 data-pop_element_schema="'.esc_attr($pop_element_schema).'"
1831 data-htmlPop_element_schema="'.esc_attr($htmlPop_element_schema).'"
1832 data-list="'.esc_attr($list).'"
1833 data-disabled-interactions="';
1834 // add data-position avec ma variables
1835 foreach($this->map_interactions as $int_key=>$int_name){
1836 $attributes.=$atts[$int_key]==false ? esc_attr($int_key).', ' : '';
1837 }
1838 $attributes.='" ';
1839 }
1840 $pagination = '';
1841 if($pages && $this->pagination){
1842 global $wp_rewrite;
1843 $paged = ( get_query_var( 'page' ) ) ? absint( get_query_var( 'page' ) ) : 1;
1844 $pagination = paginate_links( array(
1845 'prev_text' => __('« Previous Events', 'event-post'),
1846 'next_text' => __('Next Events »', 'event-post'),
1847 'current' => $paged,
1848 'total' => $this->pagination['max_num_pages'],
1849 )
1850 );
1851 }
1852
1853 if($context == 'events_only'){
1854 $ret = $html;
1855 }else{
1856 $ret.=str_replace(
1857 array(
1858 '%type%',
1859 '%id%',
1860 '%class%',
1861 '%listid%',
1862 '%style%',
1863 '%attributes%',
1864 '%list%',
1865 '%pagination%',
1866 '%prev_arrow%',
1867 '%next_arrow%',
1868 '%number%'
1869 ), array(
1870 $type,
1871 $id,
1872 $class.($className ? ' '.esc_attr($className) : '').($id == 'event_geolist' && $list ? ' has-list list-'.esc_attr($list) : ' no-list'),
1873 $id . $this->list_id,
1874 (!empty($width) ? 'width:' . esc_attr($width) . ';' : '') . (!empty($height) ? 'height:' . esc_attr($height) . ';' : '') . esc_attr($style),
1875 $attributes,
1876 $html,
1877 $pagination,
1878 $prev_arrow,
1879 $next_arrow
1880 ), $container_schema
1881 );
1882 }
1883
1884 }
1885 elseif(filter_input(INPUT_POST, 'action')=='bulk_do_shortcode'){
1886 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>';
1887 }
1888 return apply_filters('eventpost_listevents', $ret, $id.$this->list_id, $atts, $events, $context);
1889 }
1890
1891
1892 /**
1893 * Get events
1894 *
1895 * @param array $atts
1896 *
1897 * @filter eventpost_params
1898 * @filter eventpost_get_items
1899 *
1900 * @return array of post_ids which are events
1901 */
1902 public function get_events($atts) {
1903 if(isset($atts['future'])){
1904 $atts['future'] = filter_var( $atts['future'], FILTER_VALIDATE_BOOLEAN);
1905 }
1906 if(isset($atts['past'])){
1907 $atts['past'] = filter_var( $atts['past'], FILTER_VALIDATE_BOOLEAN);
1908 }
1909 if(isset($atts['geo'])){
1910 $atts['geo'] = filter_var( $atts['geo'], FILTER_VALIDATE_BOOLEAN);
1911 }
1912 if(isset($atts['pages'])){
1913 $atts['pages'] = filter_var( $atts['pages'], FILTER_VALIDATE_BOOLEAN);
1914 }
1915
1916
1917
1918 $requete = (shortcode_atts(apply_filters('eventpost_params', array(
1919 'nb' => 5,
1920 'future' => true,
1921 'past' => false,
1922 'geo' => 0,
1923 'cat' => '',
1924 'tag' => '',
1925 'date' => '',
1926 'orderby' => 'meta_value',
1927 'orderbykey' => $this->META_START,
1928 'order' => 'ASC',
1929 'tax_name' => '',
1930 'tax_term' => '',
1931 'paged' => 1,
1932 'post_type'=> $this->settings['posttypes']
1933 ), 'get_events'), $atts));
1934 if(!isset($requete['paged']) || $requete['paged'] == ""){
1935 $requete['paged'] = ( get_query_var( 'page' ) ) ? absint( get_query_var( 'page' ) ) : 1;
1936 }
1937 extract($requete);
1938 wp_reset_query();
1939
1940
1941 $arg = array(
1942 'post_status' => 'publish',
1943 'post_type' => $post_type,
1944 'posts_per_page' => $nb,
1945 'paged' => $paged,
1946 'meta_key' => $orderbykey,
1947 'orderby' => $orderby,
1948 'order' => $order
1949 );
1950
1951 if($tax_name=='category'){
1952 $tax_name='';
1953 $cat=$tax_term;
1954 }
1955 elseif($tax_name=='post-tag'){
1956 $tax_name='';
1957 $tag=$tax_term;
1958 }
1959
1960 // CUSTOM TAXONOMY
1961 if ($tax_name != '' && $tax_term != '') {
1962 $arg['tax_query'] = array(
1963 array(
1964 'taxonomy' => $tax_name,
1965 'field' => 'slug',
1966 'terms' => $tax_term,
1967 ),
1968 );
1969 }
1970 // CAT
1971 if ($cat != '') {
1972 if (preg_match('/[a-zA-Z]/i', $cat)) {
1973 $arg['category_name'] = $cat;
1974 } else {
1975 $arg['cat'] = $cat;
1976 }
1977 }
1978 // TAG
1979 if ($tag != '') {
1980 $arg['tag'] = $tag;
1981 }
1982 // DATES
1983 $meta_query = array(
1984 array(
1985 'key' => $this->META_END,
1986 'value' => '',
1987 'compare' => '!='
1988 ),
1989 array(
1990 'key' => $this->META_END,
1991 'value' => '0:0:00 0:',
1992 'compare' => '!='
1993 ),
1994 array(
1995 'key' => $this->META_END,
1996 'value' => ':00',
1997 'compare' => '!='
1998 ),
1999 array(
2000 'key' => $this->META_START,
2001 'value' => '',
2002 'compare' => '!='
2003 ),
2004 array(
2005 'key' => $this->META_START,
2006 'value' => '0:0:00 0:',
2007 'compare' => '!='
2008 )
2009 );
2010 if ($future == 0 && $past == 0) {
2011 $meta_query = array();
2012 $arg['meta_key'] = null;
2013 $arg['orderby'] = null;
2014 $arg['order'] = null;
2015 }
2016 elseif ($future == 1 && $past == 0) {
2017 $meta_query[] = array(
2018 'key' => $this->META_END,
2019 'value' => current_time('mysql'),
2020 'compare' => '>=',
2021 //'type'=>'DATETIME'
2022 );
2023 }
2024 elseif ($future == 0 && $past == 1) {
2025 $meta_query[] = array(
2026 'key' => $this->META_END,
2027 'value' => current_time('mysql'),
2028 'compare' => '<=',
2029 //'type'=>'DATETIME'
2030 );
2031 }
2032 if ($date != '') {
2033 $date = date('Y-m-d', $date);
2034
2035 $meta_query = array(
2036 array(
2037 'key' => $this->META_END,
2038 'value' => $date . ' 00:00:00',
2039 'compare' => '>=',
2040 'type' => 'DATETIME'
2041 ),
2042 array(
2043 'key' => $this->META_START,
2044 'value' => $date . ' 23:59:59',
2045 'compare' => '<=',
2046 'type' => 'DATETIME'
2047 )
2048 );
2049 }
2050 // GEO
2051 if ($geo == 1) {
2052 $meta_query[] = array(
2053 'key' => $this->META_LAT,
2054 'value' => '',
2055 'compare' => '!='
2056 );
2057 $meta_query[] = array(
2058 'key' => $this->META_LONG,
2059 'value' => '',
2060 'compare' => '!='
2061 );
2062 $arg['meta_key'] = $this->META_LAT;
2063 $arg['orderby'] = 'meta_value';
2064 $arg['order'] = 'DESC';
2065 }
2066
2067 $arg['meta_query'] = $meta_query;
2068
2069 $query_md5 = 'eventpost_' . md5(wp_json_encode($requete, true));
2070 // Check if cache is activated
2071 if ($this->settings['cache'] == 1 && false !== ( $cached_events = get_transient($query_md5) )) {
2072 return apply_filters('eventpost_get_items', is_array($cached_events) ? $cached_events : array(), $requete, $arg);
2073 }
2074
2075 $events = apply_filters('eventpost_get', '', $requete, $arg);
2076 if ('' === $events) {
2077 global $wpdb;
2078 $query = new WP_Query($arg);
2079 $events = $wpdb->get_col($query->request);
2080 $this->pagination = array(
2081 'found_posts' => $query->found_posts,
2082 'max_num_pages' => $query->max_num_pages,
2083 );
2084 foreach ($events as $k => $post) {
2085 $event = $this->retreive($post);
2086 if ($event != false){
2087 $events[$k] = $event;
2088 }
2089 }
2090 }
2091 if ($this->settings['cache'] == 1){
2092 set_transient($query_md5, $events, 5 * MINUTE_IN_SECONDS);
2093 }
2094 return apply_filters('eventpost_get_items', $events, $requete, $arg);
2095 }
2096
2097 /**
2098 * Checks if the given event is in the future or not
2099 *
2100 * @param object $event
2101 * @param boolean $exact Future status has to be calculated against time or entire day
2102 *
2103 * @return boolean
2104 */
2105 function is_future($event, $exact=false){
2106 $match = current_time('timestamp');
2107 // if EXACT is false, end date is set to begining of the current day
2108 if(!$exact){
2109 $match = mktime(0, 0, 0, date('m', $match), date('d', $match), date('Y', $match));
2110 }
2111 return ($event->time_end >= $match);
2112 }
2113
2114 /**
2115 * Checks if the given event is completed or not
2116 *
2117 * @param object $event
2118 * @param boolean $exact Past status has to be calculated against time or entire day
2119 *
2120 * @return boolean
2121 */
2122 function is_past($event, $exact=false){
2123 $match = current_time('timestamp');
2124 // if EXACT is false or full day event, end date is set to end of the current day
2125 if(!$exact || ( date('H:i:s', $event->time_start) == '00:00:00' && date('H:i:s', $event->time_end) == '00:00:00' )){
2126 $match = mktime(23, 59, 59, date('m', $match), date('d', $match), date('Y', $match));
2127 }
2128 return ($event->time_end < $match);
2129 }
2130
2131 /**
2132 * Checks if an event is online
2133 *
2134 * @param $event
2135 *
2136 * @return boolean
2137 */
2138 function is_online($event){
2139 return (in_array($event->attendance_mode, array('MixedEventAttendanceMode', 'OnlineEventAttendanceMode')));
2140 }
2141
2142 /**
2143 * Checks if an event is offline
2144 *
2145 * @param $event
2146 *
2147 * @return boolean
2148 */
2149 function is_offline($event){
2150 return (in_array($event->attendance_mode, array('MixedEventAttendanceMode', 'OfflineEventAttendanceMode')));
2151 }
2152
2153 /**
2154 * Populates a WP_Post object with event datas
2155 *
2156 * @param object $event
2157 *
2158 * @return object
2159 */
2160 public function retreive($event = null) {
2161 global $EventPost_cache;
2162 $ob = get_post($event);
2163 if(!$ob){
2164 return false;
2165 }
2166 if(is_object($ob) && $ob->start){
2167 return $ob;
2168 }
2169 if(is_object($ob) && isset($EventPost_cache[$ob->ID])){
2170 return $EventPost_cache[$ob->ID];
2171 }
2172 $ob->start = get_post_meta($ob->ID, $this->META_START, true);
2173 $ob->end = get_post_meta($ob->ID, $this->META_END, true);
2174 if (!$this->dateisvalid($ob->start)){
2175 $ob->start = '';
2176 }
2177 if (!$this->dateisvalid($ob->end)){
2178 $ob->end = '';
2179 }
2180 $ob->root_ID = $ob->ID;
2181 $ob->time_start = !empty($ob->start) ? strtotime($ob->start) : '';
2182 $ob->time_end = !empty($ob->end) ? strtotime($ob->end) : '';
2183 $ob->virtual_location = get_post_meta($ob->ID, $this->META_VIRTUAL_LOCATION, true);
2184 $ob->virtual_location = esc_url($ob->virtual_location);
2185 $ob->organization = get_post_meta($ob->ID, $this->META_ORGANIZATION, true);
2186 $ob->offer = get_post_meta($ob->ID, $this->META_OFFER, true);
2187 if(empty($ob->offer)){
2188 $ob->offer = array(
2189 'url' => null,
2190 'price' => null,
2191 'currency' => null,
2192 );
2193 }
2194 $ob->address = get_post_meta($ob->ID, $this->META_ADD, true);
2195 $ob->lat = $this->sanitize_coordinate(get_post_meta($ob->ID, $this->META_LAT, true));
2196 $ob->long = $this->sanitize_coordinate(get_post_meta($ob->ID, $this->META_LONG, true));
2197 $ob->attendance_mode = (null != $att_mod = get_post_meta($ob->ID, $this->META_ATTENDANCE_MODE, true)) ? $att_mod : array_keys($this->attendance_modes)[0];
2198 $ob->status = (null != $status = get_post_meta($ob->ID, $this->META_STATUS, true)) ? $status : array_keys($this->statuses)[0];
2199 $ob->color = $this->get_post_color($ob->ID);
2200 $ob->icon = $this->get_post_icon($ob->ID);
2201 $ob->Taxonomies = get_the_category($ob->ID);
2202 $ob->permalink = get_permalink($ob->ID);
2203 $ob->blog_id = get_current_blog_id();
2204 $ob->description = $ob->post_excerpt ? $ob->post_excerpt : str_replace('&nbsp;', ' ', preg_replace("/\n+/", "\n", trim(wp_strip_all_tags(excerpt_remove_blocks($ob->post_content)))));
2205 $EventPost_cache[$ob->ID] = apply_filters('eventpost_retreive', $ob);
2206 return $EventPost_cache[$ob->ID];
2207 }
2208
2209 /**
2210 * Fetch terms of a post
2211 *
2212 * @param mixed $_term
2213 * @param string $taxonomy
2214 * @param string $post_type
2215 */
2216 public function retreive_term($_term=null, $taxonomy='category', $post_type='post') {
2217 $term = get_term($_term, $taxonomy);
2218
2219 if(!$term){
2220 return $term;
2221 }
2222
2223 $term->start = $term->end = $term->time_start = $term->time_end = Null;
2224
2225 $request = array(
2226 'post_type'=>$post_type,
2227 'tax_name'=>$term->taxonomy,
2228 'tax_term'=>$term->slug,
2229 'future'=>true,
2230 'past'=>true,
2231 'nb'=>-1,
2232 'order'=>'ASC'
2233 );
2234
2235 $events = $this->get_events($request);
2236
2237 $term->events_count = count($events);
2238 if($term->events_count){
2239 $term->start = $events[0]->start;
2240 $term->time_start = $events[0]->time_start;
2241 $term->end = $events[$term->events_count-1]->end;
2242 $term->time_end = $events[$term->events_count-1]->time_end;
2243 }
2244
2245 $request['order']='DESC';
2246 $request['nb']=1;
2247 $request['orderbykey']=$this->META_END;
2248 $events = $this->get_events($request);
2249 if(count($events)){
2250 $term->end = $events[0]->end;
2251 $term->time_end = $events[0]->time_end;
2252 }
2253
2254 return $term;
2255
2256 }
2257
2258 // ADMIN ISSUES
2259
2260 /**
2261 * Add custom boxes in posts edit page
2262 */
2263 public function add_custom_box() {
2264 foreach($this->settings['posttypes'] as $posttype){
2265 add_meta_box(
2266 'event_post_date',
2267 __('Event date', 'event-post'),
2268 array(&$this, 'inner_custom_box_date'),
2269 $posttype,
2270 apply_filters('eventpost_add_custom_box_position', $this->settings['adminpos'], $posttype),
2271 'core',
2272 array(
2273 '__block_editor_compatible_meta_box' => true,
2274 )
2275 );
2276 add_meta_box(
2277 'event_post_loc',
2278 __('Location', 'event-post'),
2279 array(&$this, 'inner_custom_box_loc'),
2280 $posttype,
2281 apply_filters('eventpost_add_custom_box_position', $this->settings['adminpos'], $posttype),
2282 'core',
2283 array(
2284 '__block_editor_compatible_meta_box' => true,
2285 )
2286 );
2287 do_action('eventpost_add_custom_box', $posttype);
2288 }
2289 }
2290
2291 /**
2292 * Displays the date custom box
2293 */
2294 public function inner_custom_box_date() {
2295
2296
2297
2298 wp_nonce_field(plugin_basename(__FILE__), 'eventpost_nonce');
2299 $post_id = get_the_ID();
2300 $event = $this->retreive($post_id);
2301 if ($event != false){
2302 $start_date = $event->start;
2303 $end_date = $event->end;
2304 $eventcolor = $event->color;
2305 $eventicon = $event->icon;
2306
2307 $language = get_bloginfo('language');
2308 if (strpos($language, '-') > -1) {
2309 $language = strtolower(substr($language, 0, 2));
2310 }
2311 $colors = $this->get_colors();
2312 include (plugin_dir_path(__FILE__) . 'views/admin/custombox-date.php');
2313 do_action ('eventpost_custom_box_date', $event);
2314 }
2315 }
2316
2317 /**
2318 * Displays the location custom box
2319 */
2320 public function inner_custom_box_loc($post) {
2321 $event = $this->retreive($post);
2322 if ($event != false){
2323 include (plugin_dir_path(__FILE__) . 'views/admin/custombox-location.php');
2324 do_action ('eventpost_custom_box_loc', $event);
2325 $this->load_map_scripts();
2326 }
2327 }
2328
2329 public function icon_color_fields($item_id, $meta_color,$value_color,$meta_icon,$value_icon ){
2330 ?>
2331 <div class="eventpost-misc-pub-section event-color-section">
2332 <span class="screen-reader-text"><?php esc_html_e('Color:', 'event-post'); ?></span>
2333
2334 <input class="color-field-post eventpost-colorpicker"
2335 type="text"
2336 name="<?php echo esc_attr($meta_color); ?>"
2337 value="<?php echo esc_attr($value_color); ?>"
2338 id="color-field<?php echo esc_attr($item_id); ?>"/>
2339
2340 <select style="font-family : dashicons;" class="eventpost-iconpicker" name="<?php echo esc_attr($meta_icon); ?>">
2341 <option value=""><?php esc_attr_e('None','event-post') ?></option>
2342 <?php
2343 foreach($this->DashIcons->icons as $class => $unicode){
2344 ?>
2345 <option value="<?php echo esc_attr($class) ?>" <?php selected($value_icon, $class, true); ?>>&#x<?php esc_attr_e($unicode) ?>; <?php echo esc_html($class) ?></option>
2346 <?php
2347 }
2348 ?>
2349 </select>
2350 <div class="custom-marker-container">
2351 <p><?php esc_html_e('An image was found in your custom folder for this color', 'event-post')?> <span class="color-hex"></span> </p>
2352 <img src="" class="image-marker">
2353 </div>
2354 </div>
2355
2356
2357 <?php
2358 }
2359
2360 /**
2361 * Quick edit
2362 *
2363 * @param string $column_name
2364 * @param boolean $bulk
2365 */
2366 function quick_edit( $column_name, $post_type, $bulk=false) {
2367
2368 if ($bulk) {
2369 static $eventpostprintNonceBulk = TRUE;
2370 if ($eventpostprintNonceBulk) {
2371 $eventpostprintNonceBulk = FALSE;
2372 }
2373 $fields = $this->bulk_edit_fields;
2374 echo '<input type="hidden" name="eventpost-bulk-editor" id="eventpost-bulk-editor" value="eventpost-bulk-editor">';
2375 }
2376 else {
2377 static $eventpostprintNonce = TRUE;
2378 if ($eventpostprintNonce) {
2379 $eventpostprintNonce = FALSE;
2380 }
2381 $fields = $this->quick_edit_fields;
2382 }
2383 wp_nonce_field(plugin_basename(__FILE__), 'eventpost_nonce');
2384 if(isset($fields[$column_name])): ?>
2385 <fieldset class="inline-edit-col-left inline-edit-<?php echo esc_attr($column_name); ?>">
2386 <div class="inline-edit-group">
2387 <?php foreach ($fields[$column_name] as $fieldname=>$fieldlabel): ?>
2388 <fieldset class="inline-edit-col inline-edit-<?php echo esc_attr($fieldname); ?>">
2389 <div class="inline-edit-col column-<?php echo esc_attr($fieldname); ?>">
2390 <label class="inline-edit-group">
2391 <span class="title"><?php echo esc_html($fieldlabel); ?></span>
2392 <span class="input-text-wrap">
2393 <?php echo wp_kses($this->inline_field($fieldname, $bulk), $this->kses_tags); ?>
2394 </span>
2395 </label>
2396 </div>
2397 </fieldset>
2398 <?php endforeach; ?>
2399 </div>
2400 </fieldset>
2401 <?php endif;
2402 }
2403
2404 /**
2405 * Inline field in bulk edit
2406 *
2407 * @param type $fieldname
2408 *
2409 * @return string
2410 */
2411 function inline_field($fieldname, $bulk){
2412 return apply_filters('eventpost_inline_field', '<input name="'.esc_attr($fieldname).'" class="eventpost-inline-'.esc_attr($fieldname).'" value="" type="text">', $fieldname, $bulk);
2413 }
2414
2415 function inline_field_color($html, $fieldname, $bulk){
2416 if($fieldname==$this->META_COLOR){
2417 $html='';
2418 if($bulk){
2419 $html.= '<span class="eventpost-bulk-colorpicker-button link">'.esc_html(__('No Change', 'event-post')).'</span>';
2420 }
2421 $html .= '
2422
2423 <input class="eventpost-inline-colorpicker eventpost-inline-'.esc_attr($fieldname).' '.($bulk?'is-bulk':'no-bulk').'" type="color" name="'.esc_attr($fieldname).'" >';
2424 }
2425 return $html;
2426 }
2427 function inline_field_icon($html, $fieldname, $bulk){
2428 if($fieldname==$this->META_ICON){
2429 if($bulk){
2430 $html.= '<span class="eventpost-bulk-icon-button link">'.__('No Change', 'event-post').'</span>';
2431 }
2432 $html = '<select class="eventpost-inline-colorpicker eventpost-inline-'.$fieldname.' '.($bulk?'is-bulk':'no-bulk').'"
2433 type="text"
2434 name="'.$fieldname.'"
2435 style="font-family : dashicons">
2436 <option value="">'.__("None", 'event-post').'</option>';
2437 foreach($this->DashIcons->icons as $class => $unicode){
2438 $html .= '<option value="'.$class.'">&#x'.$unicode.'; '.$class.'</option>';
2439 }
2440 $html .= '</select>';
2441
2442 }
2443 return $html;
2444 }
2445
2446
2447 /**
2448 * Bulk edit
2449 *
2450 * @param type $column_name
2451 * @param type $post_type
2452 */
2453 function bulk_edit($column_name, $post_type){
2454 $this->quick_edit($column_name, $post_type, true);
2455 }
2456
2457 /**
2458 * Saves data from quick-edit via `wp_ajax_inline-save` action
2459 *
2460 * @return void
2461 */
2462 function inline_save(){
2463 $post_id = filter_input(INPUT_POST, 'post_ID', FILTER_SANITIZE_NUMBER_INT);
2464 $this->save_postdata($post_id);
2465 }
2466 /**
2467 * When the post is saved, saves our custom data
2468 *
2469 * @param int $post_id
2470 *
2471 * @return void
2472 */
2473 public function save_postdata($post_id) {
2474 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE){
2475 return;
2476 }
2477
2478 if (!wp_verify_nonce(filter_input(INPUT_POST, 'eventpost_nonce'), plugin_basename(__FILE__))){
2479 return;
2480 }
2481
2482 // Clean color or no color
2483 if (false !== $color = filter_input(INPUT_POST, $this->META_COLOR)) {
2484 update_post_meta($post_id, $this->META_COLOR, sanitize_text_field($color));
2485 }
2486 // Clean color or no color
2487 if (false !== $icon = filter_input(INPUT_POST, $this->META_ICON)) {
2488 update_post_meta($post_id, $this->META_ICON, sanitize_text_field($icon));
2489 }
2490 if (false !== $attendance_mode = filter_input(INPUT_POST, $this->META_ATTENDANCE_MODE)) {
2491 update_post_meta($post_id, $this->META_ATTENDANCE_MODE, sanitize_text_field($attendance_mode));
2492 }
2493 if (false !== $status = filter_input(INPUT_POST, $this->META_STATUS)) {
2494 update_post_meta($post_id, $this->META_STATUS, sanitize_text_field($status));
2495 }
2496 $virtual_location = filter_input(INPUT_POST, $this->META_VIRTUAL_LOCATION, FILTER_SANITIZE_URL);
2497 if ($virtual_location !== null && $virtual_location !== false) {
2498 update_post_meta($post_id, $this->META_VIRTUAL_LOCATION, sanitize_url($virtual_location));
2499 }
2500 if (false !== $organization = filter_input(INPUT_POST, $this->META_ORGANIZATION)) {
2501 update_post_meta($post_id, $this->META_ORGANIZATION, sanitize_text_field($organization));
2502 }
2503 $offer_url = filter_input(INPUT_POST, "{$this->META_OFFER}_url", FILTER_SANITIZE_URL);
2504 $offer_price = filter_input(INPUT_POST, "{$this->META_OFFER}_price");
2505 $offer_currency = filter_input(INPUT_POST, "{$this->META_OFFER}_currency");
2506 if ($offer_url || ($offer_price && $offer_currency) ) {
2507 // Format floating
2508 $offer_price = $offer_price ? str_replace(',', '.', $offer_price) : null;
2509 update_post_meta($post_id, $this->META_OFFER, array(
2510 'url' => $offer_url ? sanitize_text_field($offer_url) : null,
2511 'price' => $offer_price ? (float) $offer_price : null,
2512 'currency' => $offer_currency ? sanitize_text_field($offer_currency) : null,
2513 ));
2514 }
2515 else{
2516 delete_post_meta($post_id, $this->META_OFFER);
2517 }
2518 // Clean date or no date
2519 if ((false !== $start = filter_input(INPUT_POST, $this->META_START)) &&
2520 (false !== $end = filter_input(INPUT_POST, $this->META_END)) &&
2521 '' != $start &&
2522 '' != $end) {
2523 update_post_meta($post_id, $this->META_START, sanitize_text_field(substr($start,0,16).':00'));
2524 update_post_meta($post_id, $this->META_END, sanitize_text_field(substr($end,0,16).':00'));
2525 }
2526 else {
2527 delete_post_meta($post_id, $this->META_START);
2528 delete_post_meta($post_id, $this->META_END);
2529 }
2530
2531 // Clean location or no location
2532 if ((false !== $lat = filter_input(INPUT_POST, $this->META_LAT)) &&
2533 (false !== $long = filter_input(INPUT_POST, $this->META_LONG)) &&
2534 '' != $lat &&
2535 '' != $long) {
2536 update_post_meta($post_id, $this->META_ADD, sanitize_text_field(filter_input(INPUT_POST, $this->META_ADD)));
2537 update_post_meta($post_id, $this->META_LAT, $this->sanitize_coordinate(sanitize_text_field($lat)));
2538 update_post_meta($post_id, $this->META_LONG, $this->sanitize_coordinate(sanitize_text_field($long)));
2539 }
2540 else {
2541 delete_post_meta($post_id, $this->META_ADD);
2542 delete_post_meta($post_id, $this->META_LAT);
2543 delete_post_meta($post_id, $this->META_LONG);
2544 }
2545
2546 $post_ids = (!empty($_POST['post_ids']) ) ? $_POST['post_ids'] : array();
2547 }
2548
2549 /**
2550 * Saves data from bulk-edit
2551 * Uses bulk_edit_posts hook
2552 *
2553 * @see https://developer.wordpress.org/reference/hooks/bulk_edit_posts/
2554 *
2555 * @return void
2556 */
2557 function save_bulkdatas(array $post_ids, array $shared_post_data) {
2558 if (!wp_verify_nonce(filter_input(INPUT_GET, 'eventpost_nonce'), plugin_basename(__FILE__))){
2559 return;
2560 }
2561 $current_post_type = isset($shared_post_data['post_type']) ? $shared_post_data['post_type'] : 'post';
2562 if (in_array($current_post_type, $this->settings['posttypes'])) {
2563 if (!empty($post_ids) && is_array($post_ids)) {
2564 foreach ($post_ids as $post_id) {
2565 if(! current_user_can( 'edit_post', $post_id )){
2566 continue;
2567 }
2568 foreach ($this->bulk_edit_fields as $sets) {
2569 foreach ($sets as $fieldname => $fieldlabel) {
2570 if (isset($shared_post_data[$fieldname])) {
2571 update_post_meta($post_id, $fieldname, $shared_post_data[$fieldname]);
2572 }
2573 }
2574 }
2575 }
2576 }
2577 }
2578 }
2579
2580 /**
2581 * Displays a date for calendar cell
2582 *
2583 * @param string $date
2584 * @param string $cat
2585 * @param boolean $display
2586 *
2587 * @return boolean
2588 */
2589 public function display_caldate($date, $cat = '', $display = false, $colored=true, $thumbnail='', $title='',$tax_name='' ,$tax_term='') {
2590 $events = $this->get_events(array('nb' => -1, 'date' => $date, 'cat' => $cat, 'retreive' => true,'tax_name' => $tax_name ,'tax_term' => $tax_term));
2591 $nb = count($events);
2592 $ret = "";
2593 $price = "";
2594 if(!$display && !$nb){
2595 $ret = date('j', $date);
2596 }
2597 $price = '';
2598 if($nb){
2599 if ($display || $title) {
2600 $ret='<ul>';
2601 foreach ($events as $event) {
2602 $price = $this->get_price($event, true);
2603 if ($this->settings['emptylink'] == 0 && empty($event->post_content)) {
2604 $event->guid = '#';
2605 }
2606 $ret.='<li>'
2607 // Translators: %s is the event title
2608 . '<a href="' . $event->permalink . '" title="'.esc_attr(sprintf(__('View event: %s', 'event-post'), $event->post_title)).'">'
2609 . '<h4>' . $event->post_title . '</h4>'
2610 . '<span class="event_price">' . $price . '</span>'
2611 .$this->get_single($event)
2612 . (!empty($thumbnail) ? '<span class="event_thumbnail_wrap">' . get_the_post_thumbnail($event->ID, $thumbnail) . '</span>' : '')
2613 .'</a>'
2614 . '</li>';
2615 }
2616 $ret.='</ul>';
2617 }
2618 if ($display) {
2619 // return $ret;
2620 }
2621 elseif($title) {
2622 $ret = '<span '.($colored?' style="color:#'.$events[0]->color.'"':'').'>'.date('j', $date).'</span>'.$ret;
2623 }
2624 else {
2625 $ret = '<button data-event="'. $tax_term .'" data-date="' . date('Y-m-d', $date).'"'
2626 .' class="'.apply_filters( 'event_post_class_calendar_link', 'eventpost_cal_link' ).'"'.($colored?' style="background-color:#'.$events[0]->color.'"':'')
2627 // Translators: %1$d is the number of events, %2$s is the date
2628 .' 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']))).'"'
2629 .'>'
2630 . date('j', $date)
2631 . '</button>';
2632 }
2633 }
2634 return apply_filters('eventpost_display_caldate', $ret, $events, $date, $cat ,$price, $display ,$colored ,$thumbnail ,$title ,$tax_name ,$tax_term );
2635 }
2636
2637
2638 /**
2639 * Returns a calendar HTML
2640 *
2641 * @param array $atts
2642 *
2643 * @filter eventpost_params
2644 *
2645 * @return string
2646 */
2647 public function calendar($atts) {
2648 extract(shortcode_atts(apply_filters('eventpost_params', array(
2649 'date' => date('Y-n'),
2650 'cat' => '',
2651 'mondayfirst' => 0, //1 : weeks starts on monday
2652 'datepicker' => 1,
2653 'colored' => 1,
2654 'display_title'=>0,
2655 'tax_name' => '',
2656 'tax_term' => '',
2657 'thumbnail'=>'',
2658 ), 'calendar'), $atts));
2659
2660 if($date && !preg_match('#[0-9][0-9][0-9][0-9]-[0-9][0-9]?#i', $date)){
2661 $date = date('Y-n', strtotime($date));
2662 }
2663 if(!$date){
2664 $date = date('Y-n');
2665 }
2666
2667 $annee = substr($date, 0, 4);
2668 $mois = substr($date, 5);
2669
2670 $time = mktime(0, 0, 0, $mois, 1, $annee);
2671
2672 $prev_year = strtotime('-1 Year', $time);
2673 $next_year = strtotime('+1 Year', $time);
2674 $prev_month = strtotime('-1 Month', $time);
2675 $next_month = strtotime('+1 Month', $time);
2676
2677 $JourMax = date("t", $time);
2678 $NoJour = -date("w", $time);
2679 if ($mondayfirst == 0) {
2680 $NoJour +=1;
2681 } else {
2682 $NoJour +=2;
2683 $this->Week[] = array_shift($this->Week);
2684 }
2685 if ($NoJour > 0 && $mondayfirst == 1) {
2686 $NoJour -=7;
2687 }
2688 $ret = '<table class="event-post-calendar-table">'
2689 . '<caption class="screen-reader-text">'
2690 . __('A calendar of events', 'event-post')
2691 . '</caption>';
2692 $ret.='<thead><tr><th colspan="7">';
2693 if ($datepicker == 1) {
2694 $ret.='<div class="eventpost-calendar-header">';
2695 // Translators: %s is the year
2696 $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">';
2697 $ret.=$annee;
2698 // Translators: %s is the year
2699 $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>';
2700 // Translators: %s is the month name
2701 $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">';
2702 $ret.=$this->NomDuMois[abs($mois)];
2703 // Translators: %s is the month name
2704 $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>';
2705 $ret.='<span class="eventpost-cal-today"><button data-date="' . date('Y-n') . '" class="eventpost_cal_bt">' . __('Today', 'event-post') . '</button></span>';
2706 $ret.='</div>';
2707 }
2708 $ret.='</th></tr><tr class="event_post_cal_days">';
2709 for ($w = 0; $w < 7; $w++) {
2710 $ret.='<th scope="col">' . strtoupper(substr($this->Week[$w], 0, 1)) . '</th>';
2711 }
2712 $ret.='</tr>';
2713 $ret.='</thead>';
2714
2715 $ret.='<tbody>';
2716 $sqldate = date('Y-m', $time);
2717 $cejour = date('Y-m-d');
2718 for ($semaine = 0; $semaine <= 5; $semaine++) { // 6 semaines par mois
2719 $tr_row_content ='';
2720 for ($journee = 0; $journee <= 6; $journee++) { // 7 jours par semaine
2721 if ($NoJour > 0 && $NoJour <= $JourMax) { // si le jour est valide a afficher
2722 $td = '<td class="event_post_day">';
2723 if ($sqldate . '-' . ($NoJour<10?'0':'').$NoJour == $cejour) {
2724 $td = '<td class="event_post_day_now">';
2725 }
2726 if ($sqldate . '-' . ($NoJour<10?'0':'').$NoJour < $cejour){
2727 $td = '<td class="event_post_day_over">'; // Patch ahf
2728 }
2729 $tr_row_content.=$td;
2730 $tr_row_content.= $this->display_caldate(mktime(0, 0, 0, $mois, $NoJour, $annee), $cat, false, $colored, $thumbnail, $display_title ,$tax_name ,$tax_term);
2731 $tr_row_content.='</td>';
2732 } else {
2733 $tr_row_content.='<td></td>';
2734 }
2735 $NoJour ++;
2736 }
2737 if($tr_row_content){
2738 $ret.='<tr>'.$tr_row_content.'</tr>';
2739 }
2740
2741 }
2742 $ret.='</tbody></table>';
2743 return $ret;
2744 }
2745
2746 /**
2747 * Echoes a list of event, should be called via AJAX
2748 *
2749 * @return void
2750 */
2751 public function ajaxlist(){
2752 echo wp_kses($this->list_events(array(
2753 'nb' => esc_attr(FILTER_INPUT(INPUT_POST, 'nb')),
2754 'future' => esc_attr(FILTER_INPUT(INPUT_POST, 'future')),
2755 'past' => esc_attr(FILTER_INPUT(INPUT_POST, 'past')),
2756 'geo' => esc_attr(FILTER_INPUT(INPUT_POST, 'geo')),
2757 'width' => esc_attr(FILTER_INPUT(INPUT_POST, 'width')),
2758 'height' => esc_attr(FILTER_INPUT(INPUT_POST, 'height')),
2759 'zoom' => esc_attr(FILTER_INPUT(INPUT_POST, 'zoom')),
2760 'tile' => esc_attr(FILTER_INPUT(INPUT_POST, 'tile')),
2761 'title' => esc_attr(FILTER_INPUT(INPUT_POST, 'title')),
2762 'before_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'before_title')),
2763 'after_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'after_title')),
2764 'cat' => esc_attr(FILTER_INPUT(INPUT_POST, 'cat')),
2765 'tag' => esc_attr(FILTER_INPUT(INPUT_POST, 'tag')),
2766 'events' => esc_attr(FILTER_INPUT(INPUT_POST, 'events')),
2767 'style' => esc_attr(FILTER_INPUT(INPUT_POST, 'style')),
2768 'thumbnail' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail')),
2769 'thumbnail_size' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail_size')),
2770 'excerpt' => esc_attr(FILTER_INPUT(INPUT_POST, 'excerpt')),
2771 'orderby' => esc_attr(FILTER_INPUT(INPUT_POST, 'orderby')),
2772 'order' => esc_attr(FILTER_INPUT(INPUT_POST, 'order')),
2773 'class' => esc_attr(FILTER_INPUT(INPUT_POST, 'class')),
2774 'pages' => esc_attr(FILTER_INPUT(INPUT_POST, 'pages')),
2775 ), esc_attr(FILTER_INPUT(INPUT_POST, 'list_type'))), $this->kses_tags);
2776 exit;
2777 }
2778
2779 /**
2780 * Echoes a list of event, should be called via AJAX
2781 *
2782 * @return void
2783 */
2784 public function ajaxTimeline(){
2785 echo wp_kses($this->list_events(array(
2786 'nb' => esc_attr(FILTER_INPUT(INPUT_POST, 'nb')),
2787 'future' => esc_attr(FILTER_INPUT(INPUT_POST, 'future')),
2788 'past' => esc_attr(FILTER_INPUT(INPUT_POST, 'past')),
2789 'geo' => esc_attr(FILTER_INPUT(INPUT_POST, 'geo')),
2790 'width' => esc_attr(FILTER_INPUT(INPUT_POST, 'width')),
2791 'height' => esc_attr(FILTER_INPUT(INPUT_POST, 'height')),
2792 'zoom' => esc_attr(FILTER_INPUT(INPUT_POST, 'zoom')),
2793 'tile' => esc_attr(FILTER_INPUT(INPUT_POST, 'tile')),
2794 'title' => esc_attr(FILTER_INPUT(INPUT_POST, 'title')),
2795 'before_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'before_title')),
2796 'after_title' => esc_attr(FILTER_INPUT(INPUT_POST, 'after_title')),
2797 'cat' => esc_attr(FILTER_INPUT(INPUT_POST, 'cat')),
2798 'tag' => esc_attr(FILTER_INPUT(INPUT_POST, 'tag')),
2799 'events' => esc_attr(FILTER_INPUT(INPUT_POST, 'events')),
2800 'style' => esc_attr(FILTER_INPUT(INPUT_POST, 'style')),
2801 'thumbnail' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail')),
2802 'thumbnail_size' => esc_attr(FILTER_INPUT(INPUT_POST, 'thumbnail_size')),
2803 'excerpt' => esc_attr(FILTER_INPUT(INPUT_POST, 'excerpt')),
2804 'orderby' => esc_attr(FILTER_INPUT(INPUT_POST, 'orderby')),
2805 'order' => esc_attr(FILTER_INPUT(INPUT_POST, 'order')),
2806 'class' => esc_attr(FILTER_INPUT(INPUT_POST, 'class')),
2807 'pages' => esc_attr(FILTER_INPUT(INPUT_POST, 'pages')),
2808 ), esc_attr(FILTER_INPUT(INPUT_POST, 'list_type'))), $this->kses_tags);
2809 exit;
2810 }
2811 /**
2812 * Echoes next page of events, should be called via AJAX
2813 *
2814 * @return void
2815 */
2816 public function ajaxGetNextPage(){
2817 $response = [
2818 "success" => false,
2819 "next_query" => false,
2820 ];
2821 if(isset($_POST['query'])){
2822 parse_str($_POST['query'],$query);
2823 foreach($query as $key => $value){
2824 $query[$key] = esc_attr($value);
2825 }
2826 if(isset($_POST['paged'])){
2827 $query["paged"] = esc_attr($_POST['paged']);
2828 }else{
2829 $response['message'] = __('Page number missing', 'event-post');
2830 }
2831 $query['container_schema'] = $this->timeline_shema['container'];
2832 $query['item_schema'] = $this->timeline_shema['item'];
2833 $html = $this->list_events($query,'event_timeline','events_only');
2834 if($html == ""){
2835 $response['message'] = __('No more to load', 'event-post');
2836 }else{
2837 $query["paged"] = $query["paged"] + 1;
2838 $next_html = $this->list_events($query,'event_timeline','events_only');
2839 $response = [
2840 "success" => true,
2841 "html" => $html,
2842 "next_query" => $next_html == "" ? false : true,
2843 ];
2844 }
2845 }else{
2846 $response['message'] = __('Query missing', 'event-post');
2847 }
2848 wp_send_json($response);
2849 exit;
2850 }
2851
2852 /**
2853 * Echoes the content of the calendar in ajax context
2854 *
2855 * @return void
2856 */
2857 public function ajaxcal() {
2858 $method = isset($_GET['action']) ? INPUT_GET : INPUT_POST;
2859 echo wp_kses($this->calendar(array(
2860 'date' => esc_attr(FILTER_INPUT($method, 'date')),
2861 'cat' => esc_attr(FILTER_INPUT($method, 'cat')),
2862 'mondayfirst' => esc_attr(FILTER_INPUT($method, 'mf')),
2863 'datepicker' => esc_attr(FILTER_INPUT($method, 'dp')),
2864 'colored' => esc_attr(FILTER_INPUT($method, 'color')),
2865 'display_title' => esc_attr(FILTER_INPUT($method, 'display_title')),
2866 'thumbnail' => esc_attr(FILTER_INPUT($method, 'thumbnail')),
2867 'tax_name' => esc_attr(FILTER_INPUT($method, 'tax_name')),
2868 'tax_term' => esc_attr(FILTER_INPUT($method, 'tax_term')),
2869 )), $this->kses_tags);
2870 exit();
2871 }
2872
2873 /**
2874 * Echoes the date of the calendar in ajax context
2875 */
2876 public function ajaxdate() {
2877 echo wp_kses($this->display_caldate(
2878 strtotime(esc_attr(FILTER_INPUT(INPUT_GET, 'date'))),
2879 esc_attr(FILTER_INPUT(INPUT_GET, 'cat')),
2880 true,
2881 esc_attr(FILTER_INPUT(INPUT_GET, 'color')),
2882 esc_attr(FILTER_INPUT(INPUT_GET, 'thumbnail')),
2883 esc_attr(FILTER_INPUT(INPUT_GET, 'display_title')),
2884 esc_attr(FILTER_INPUT(INPUT_GET, 'tax_name')),
2885 esc_attr(FILTER_INPUT(INPUT_GET, 'tax_term'))
2886 ), $this->kses_tags);
2887 exit();
2888 }
2889
2890 /**
2891 * Echoes a date in ajax context
2892 */
2893 public function HumanDate() {
2894 if (isset($_REQUEST['date']) && !empty($_REQUEST['date'])) {
2895 $date = strtotime($_REQUEST['date']);
2896 echo esc_html($this->human_date($date, $this->settings['dateformat']).(date('H:i', $date)=='00:00' ? '' : ' '. date($this->settings['timeformat'], $date)));
2897 exit();
2898 }
2899 }
2900
2901 /**
2902 * Displays a search form
2903 *
2904 * @param type $atts
2905 *
2906 * @return type
2907 */
2908 public function search($atts) {
2909 $params = shortcode_atts(apply_filters('eventpost_params', array(
2910 'dates' => true,
2911 'q' => true,
2912 'tax' => false,
2913 ), 'search'), $atts);
2914 $this->list_id++;
2915
2916 $list_id = $this->list_id;
2917 $q = (false !== $q = filter_input(INPUT_GET, 'q')) ? $q : '';
2918 $from = (false !== $from = filter_input(INPUT_GET, 'from')) ? $from : '';
2919 $to = (false !== $to = filter_input(INPUT_GET, 'to')) ? $to : '';
2920 $tax = (false !== $tax = filter_input(INPUT_GET, 'tax')) ? $tax : '';
2921
2922 $cleaned_from = $this->date_cleanup($from);
2923 $cleaned_to = $this->date_cleanup($to);
2924 if(empty($cleaned_from)){
2925 $from=false;
2926 }
2927 if(empty($cleaned_to)){
2928 $to=false;
2929 }
2930
2931 // Search form
2932 $this->admin_scripts(null, true);
2933 wp_enqueue_style('jquery-ui', plugins_url('/css/jquery-ui.css', __FILE__), false, filemtime( "/$block_js" ));
2934 include (plugin_dir_path(__FILE__) . 'views/search-form.php');
2935
2936 // Results
2937 if ($list_id == filter_input(INPUT_GET, 'evenpost_search')) {
2938 $arg = array(
2939 'post_type' => $this->settings['posttypes'],
2940 'meta_key' => $this->META_START,
2941 'orderby' => 'meta_value',
2942 'order' => 'ASC',
2943 's' => $q
2944 );
2945 if ($tax) {
2946 $arg['cat'] = $tax;
2947 }
2948
2949 if ($from || $to) {
2950
2951 $arg['meta_query'] = array();
2952 if ($from) {
2953 $arg['meta_query'][] = array(
2954 'key' => $this->META_START,
2955 'value' => $from,
2956 'compare' => '>=',
2957 'type' => 'DATETIME'
2958 );
2959 }
2960 if ($to) {
2961 $arg['meta_query'][] = $meta_query = array(
2962 array(
2963 'key' => $this->META_END,
2964 'value' => $to,
2965 'compare' => '<=',
2966 'type' => 'DATETIME'
2967 ),
2968 );
2969 }
2970 }
2971 $events = new WP_Query($arg);
2972 include (plugin_dir_path(__FILE__) . 'views/search-results.php');
2973 wp_reset_query();
2974 }
2975 }
2976
2977 /**
2978 * Geocodes an address using OpenStreetMap Nominatim API and cache the result in a transient for 30 days
2979 *
2980 * @param string $address
2981 * @param boolean $single_result Whether to return only the first result or all results
2982 *
2983 * @return array|false|string The geocoding result(s) or false on failure
2984 */
2985 public function geocode(string $address, bool $single_result = false){
2986 $transient_name = 'eventpost_osquery_' . $address;
2987 $val = get_transient($transient_name);
2988 if (false === $val || empty($val) || !is_string($val)) {
2989 $language = get_bloginfo('language');
2990 if (strpos($language, '-') > -1) {
2991 $language = strtolower(substr($language, 0, 2));
2992 }
2993 $remote_val = wp_safe_remote_request('https://nominatim.openstreetmap.org/search?q=' . rawurlencode($address) . '&format=json&accept-language=' . $language, [
2994 'user-agent' => getenv('HTTP_USER_AGENT') ?? 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url'),
2995 'headers' => [
2996 'Referer' => get_bloginfo('url'),
2997 ],
2998 'timeout' => 5,
2999 ]);
3000 $remote_body = wp_remote_retrieve_body($remote_val);
3001 if(strstr($remote_body, '<html>')){
3002 $val = [
3003 [
3004 'lat' => '',
3005 'lon' => '',
3006 'display_name' => strip_tags($remote_body),
3007 ]
3008 ];
3009 }
3010 else{
3011 $val = json_decode($remote_body);
3012 if($val){
3013 set_transient($transient_name, $val, 30 * DAY_IN_SECONDS);
3014 }
3015 }
3016 }
3017 if($single_result && is_array($val) && count($val) > 0){
3018 $val = $val[0];
3019 }
3020 return $val;
3021 }
3022
3023 /**
3024 * AJAX Get lat long from address
3025 */
3026 public function GetLatLong() {
3027 if (isset($_REQUEST['q']) && !empty($_REQUEST['q'])) {
3028 // verifier le cache
3029 $q = $_REQUEST['q'];
3030 header('Content-Type: application/json');
3031 $val = $this->geocode($q);
3032 wp_send_json( $val );
3033 exit();
3034 }
3035 }
3036
3037 /**
3038 * Alters columns
3039 *
3040 * @param array $defaults
3041 *
3042 * @filter eventpost_columns_head
3043 *
3044 * @return array
3045 */
3046 public function columns_head($defaults) {
3047 $defaults['event'] = __('Event', 'event-post');
3048 $defaults['location'] = __('Location', 'event-post');
3049 return apply_filters('eventpost_columns_head', $defaults);
3050 }
3051
3052 /**
3053 * Echoes content of a row in a given column
3054 *
3055 * @param string $column_name
3056 * @param int $post_id
3057 *
3058 * @action eventpost_columns_content
3059 */
3060 public function columns_content($column_name, $post_id) {
3061 if ($column_name == 'location') {
3062 $lat = $this->sanitize_coordinate(get_post_meta($post_id, $this->META_LAT, true));
3063 $lon = $this->sanitize_coordinate(get_post_meta($post_id, $this->META_LONG, true));
3064
3065 if (!empty($lat) && !empty($lon)) {
3066 add_thickbox();
3067 $color = $this->get_post_color($post_id, $this->settings['default_color'], true);
3068 $icon = $this->get_post_icon($post_id, $this->settings['default_icon'], true);
3069 if ($color == ''){
3070 $color = '777777';
3071 }
3072 if ($icon == ''){
3073 $icon = 'location';
3074 }
3075 echo wp_kses( '<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">'
3076 . '<i class="dashicons dashicons-'.$icon.'" style="color:#'.$color.';"></i>'
3077 . '<span class="screen-reader-text">'.__('View on a map', 'event-post').'</span>'
3078 . get_post_meta($post_id, $this->META_ADD, true)
3079 . '</a> ', $this->kses_tags);
3080 }
3081 $this->column_edit_hidden_fields($post_id, 'location');
3082 }
3083 if ($column_name == 'event') {
3084 echo wp_kses($this->print_date($post_id, false), $this->kses_tags);
3085 $this->column_edit_hidden_fields($post_id, 'event');
3086 }
3087 do_action('eventpost_columns_content', $column_name, $post_id);
3088 }
3089
3090 function column_edit_hidden_fields($post_id, $set){
3091 $event = $this->retreive($post_id);
3092 $html = '<div class="hidden">';
3093 if ($event != false){
3094 foreach($this->quick_edit_fields[$set] as $fieldname=>$fieldlabel){
3095 $html .= '<span class="inline-edit-value '.$fieldname.'">'.esc_attr($event->$fieldname).'</span>';
3096 }
3097 }
3098 $html .= '</div>';
3099 echo wp_kses($html, $this->kses_tags);
3100 }
3101
3102 // ADMIN PAGES
3103
3104 /**
3105 * Adds items to the native "right now" dashboard widget
3106 *
3107 * @param array $elements
3108 *
3109 * @return array
3110 */
3111 public function dashboard_right_now($elements){
3112 $nb_date = count($this->get_events(array('future'=>1, 'past'=>1, 'nb'=>-1)));
3113 $nb_geo = count($this->get_events(array('future'=>1, 'past'=>1, 'geo'=>1, 'nb'=>-1)));
3114 if($nb_date){
3115 // Translators: %d is the number of events
3116 array_push($elements, '<i class="dashicons dashicons-calendar"></i> <i href="edit.php?post_type=post">'.sprintf(__('%d Events','event-post'), $nb_date)."</i>");
3117 }
3118 if($nb_geo){
3119 // Translators: %d is the number of geolocalized events
3120 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>");
3121 }
3122 return $elements;
3123 }
3124
3125 /*
3126 * Feed
3127 * generate ICS or VCS files from a category
3128 */
3129
3130 /**
3131 * Get a date formatted for ICS
3132 *
3133 * @param timestamp $timestamp
3134 *
3135 * @return string
3136 */
3137 public function ics_date($timestamp){
3138 return date("Ymd",$timestamp).'T'.date("His",$timestamp);
3139 }
3140
3141 public function get_gmt_offset(){
3142 $gmt_offset = get_option('gmt_offset ');
3143 $codegmt = 0;
3144 if ($gmt_offset != 0 && substr($gmt_offset, 0, 1) != '-' && substr($gmt_offset, 0, 1) != '+') {
3145 $codegmt = $gmt_offset * -1;
3146 $gmt_offset = '+' . $gmt_offset;
3147 }
3148 if(abs($gmt_offset < 10)){
3149 $gmt_offset = substr($gmt_offset, 0, 1).'0'.substr($gmt_offset, 1);
3150 }
3151 return $gmt_offset;
3152 }
3153
3154 /**
3155 * Outputs an ICS or VCS file for a given event
3156 *
3157 * @param int $event_id
3158 * @param string $format
3159 *
3160 * @return void
3161 */
3162 private function generate_ics($event_id, $format){
3163 $allowed_formats = array('ics', 'vcs');
3164 $event_id = intval($event_id);
3165 $format = sanitize_text_field($format);
3166 if (in_array($format, $allowed_formats)) {
3167 $export_file = plugin_dir_path(__FILE__) . 'inc/export/' . $format . '.php';
3168 if (is_numeric($event_id) && file_exists($export_file)) {
3169 $event = $this->retreive($event_id);
3170 include $export_file;
3171 exit;
3172 }
3173 }
3174 wp_die(esc_html__('Invalid request.', 'event-post'));
3175 }
3176
3177
3178 public function parse_request(){
3179 global $wp;
3180 if (preg_match('#^event-feed#i', $wp->request, $match)) {
3181 $this->feed();
3182 exit;
3183 }
3184 if (preg_match('#^eventpost/([0-9]*)\.(ics|vcs)#i', $wp->request, $match)) {
3185 $this->generate_ics($match[1], $match[2]);
3186 }
3187 }
3188
3189 public function export(){
3190 if(false !== $event_id=\filter_input(INPUT_GET, 'event_id',FILTER_SANITIZE_NUMBER_INT)){
3191 $format = \filter_input(INPUT_GET, 'format');
3192 $this->generate_ics($event_id, $format);
3193 }
3194 }
3195
3196
3197 /**
3198 * Outputs an ICS document
3199 *
3200 * Filters can be applied to the criteria used to retrieve events in GET parameters:
3201 * - cat : category slug
3202 * - tag : tag slug
3203 * - tax_name : custom taxonomy name
3204 * - tax_term : custom taxonomy term slug
3205 * - nb : number of events to retrieve (default 10)
3206 * - future : retreive future events
3207 * - past : retreive past events
3208 *
3209 * @return void
3210 */
3211 public function feed(){
3212 $criteria = array(
3213 'nb'=>10,
3214 );
3215 if(false !== $cat=\filter_input(INPUT_GET, 'cat')){
3216 $criteria['cat'] = sanitize_text_field($cat);
3217 }
3218 if(false !== $tag=\filter_input(INPUT_GET, 'tag')){
3219 $criteria['tag'] = sanitize_text_field($tag);
3220 }
3221 if(false !== $tax_name=\filter_input(INPUT_GET, 'tax_name')){
3222 $criteria['tax_name'] = sanitize_text_field($tax_name);
3223 }
3224 if(false !== $tax_term=\filter_input(INPUT_GET, 'tax_term')){
3225 $criteria['tax_term'] = sanitize_text_field($tax_term);
3226 }
3227 if(false !== $nb=\filter_input(INPUT_GET, 'nb', FILTER_SANITIZE_NUMBER_INT)){
3228 $criteria['nb'] = sanitize_text_field($nb);
3229 }
3230 if(false !== $future=\filter_input(INPUT_GET, 'future', FILTER_SANITIZE_NUMBER_INT)){
3231 $criteria['future'] = sanitize_text_field($future);
3232 }
3233 if(false !== $past=\filter_input(INPUT_GET, 'past', FILTER_SANITIZE_NUMBER_INT)){
3234 $criteria['past'] = sanitize_text_field($past);
3235 }
3236 $vtz = get_option('timezone_string');
3237 $gmt = $this->get_gmt_offset();
3238 date_default_timezone_set($vtz);
3239 $separator = "\n";
3240
3241 header("content-type:text/calendar");
3242 header("Pragma: public");
3243 header("Expires: 0");
3244 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
3245 header("Cache-Control: public");
3246 header("Content-Disposition: attachment; filename=". str_replace('+','-',rawurlencode(get_option('blogname').'-'.$cat)).".ics;" );
3247
3248 $props = array();
3249
3250 // General
3251 $props[] = 'BEGIN:VCALENDAR';
3252 $props[] = 'PRODID://WordPress//Event-Post-V'.$this->version.'//EN';
3253 $props[] = 'VERSION:2.0';
3254 // Timezone
3255 if(!empty($vtz)){
3256 array_push($props,
3257 'BEGIN:VTIMEZONE',
3258 'TZID:'.$vtz,
3259 'BEGIN:DAYLIGHT',
3260 'TZOFFSETFROM:+0100',
3261 'TZOFFSETTO:'.($gmt).'00',
3262 'DTSTART:19700329T020000',
3263 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3',
3264 'END:DAYLIGHT',
3265 'BEGIN:STANDARD',
3266 'TZOFFSETFROM:'.($gmt).'00',
3267 'TZOFFSETTO:+0100',
3268 'TZNAME:CET',
3269 'DTSTART:19701025T030000',
3270 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10',
3271 'END:STANDARD',
3272 'END:VTIMEZONE'
3273 );
3274 }
3275
3276 // Events
3277 $events=$this->get_events($criteria);
3278 foreach ($events as $event) {
3279 if($event->time_start && $event->time_end){
3280 $description = wordwrap(
3281 str_replace(
3282 ['\\', ';', ',', "\r", "\n"],
3283 ['\\\\', '\;', '\,', '', '\n'],
3284 wp_strip_all_tags($event->description . "\n\n" . $event->permalink)
3285 ),
3286 70,
3287 "\n ",
3288 true
3289 );
3290 array_push($props,
3291 'BEGIN:VEVENT',
3292 'CREATED:'.$this->ics_date(strtotime($event->post_date)).'Z',
3293 'LAST-MODIFIED:'.$this->ics_date(strtotime($event->post_modified)).'Z',
3294 'SUMMARY:'.$event->post_title,
3295 'UID:'.md5(site_url()."_eventpost_".$event->ID),
3296 'LOCATION:'.str_replace(',','\,',$event->address),
3297 'DTSTAMP:'.$this->ics_date($event->time_start).(!empty($vtz)?'':'Z'),
3298 'DTSTART'.(!empty($vtz)?';TZID='.$vtz:'').':'.$this->ics_date($event->time_start).(!empty($vtz)?'':'Z'),
3299 'DTEND'.(!empty($vtz)?';TZID='.$vtz:'').':'.$this->ics_date($event->time_end).(!empty($vtz)?'':'Z'),
3300 'DESCRIPTION:'.$description,
3301 'END:VEVENT'
3302 );
3303 }
3304 }
3305
3306 // End
3307 $props[] = 'END:VCALENDAR';
3308
3309 echo esc_html(implode($separator, $props));
3310 exit;
3311 }
3312 }
3313