PluginProbe
Event Post / trunk
Event Post vtrunk
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 trunk, at eventpost.php

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