PluginProbe
Event Post / 6.1.2
Event Post v6.1.2
6.1.2 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 All 47 releases
event-post / eventpost.php

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

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