PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 3.9.0
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v3.9.0
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / ThirdParty / Googlecalendar / Embedpress_Google_Helper.php
embedpress / EmbedPress / ThirdParty / Googlecalendar Last commit date
assets 4 years ago Embedpress_Google_Helper.php 2 years ago GoogleClient.php 4 years ago
Embedpress_Google_Helper.php
976 lines
1 <?php
2
3 if ( !class_exists( 'EmbedPress_GoogleClient') ) {
4 require_once 'GoogleClient.php';
5 }
6 if ( !defined( 'EPGC_NOTICES_VERIFY_SUCCESS') ) {
7 define('EPGC_NOTICES_VERIFY_SUCCESS', __('Verify OK!', 'embedpress'));
8 define('EPGC_NOTICES_REVOKE_SUCCESS', __('Access revoked. This plugin does not have access to your calendars anymore.', 'embedpress'));
9 define('EPGC_NOTICES_REMOVE_SUCCESS', sprintf(__('Plugin data removed. Make sure to also manually revoke access to your calendars in the Google <a target="__blank" href="%s">Permissions</a> page!', 'embedpress'), 'https://myaccount.google.com/permissions'));
10 define('EPGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS', __('Calendars updated.', 'embedpress'));
11 define('EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS', __('Colors updated.', 'embedpress'));
12 define('EPGC_NOTICES_CACHE_DELETED', __('Cache deleted.', 'embedpress'));
13
14 define('EPGC_ERRORS_CLIENT_SECRET_MISSING', __('No client secret.', 'embedpress'));
15 define('EPGC_ERRORS_CLIENT_SECRET_INVALID', __('Invalid client secret.', 'embedpress'));
16 define('EPGC_ERRORS_ACCESS_TOKEN_MISSING', __('No access token.', 'embedpress'));
17 define('EPGC_ERRORS_REFRESH_TOKEN_MISSING', sprintf(__('Your refresh token is missing!<br><br>This can only be solved by manually revoking this plugin&#39;s access in the Google <a target="__blank" href="%s">Permissions</a> page and remove all plugin data.', 'embedpress'), 'https://myaccount.google.com/permissions'));
18 define('EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING', __('No access and refresh tokens.', 'embedpress'));
19 define('EPGC_ERRORS_REDIRECT_URI_MISSING', __('URI <code>%s</code> missing in the client secret file. Adjust your Google project and upload the new client secret file.', 'embedpress'));
20 define('EPGC_ERRORS_INVALID_FORMAT', __('Invalid format', 'embedpress'));
21 define('EPGC_ERRORS_NO_CALENDARS', __('No calendars', 'embedpress'));
22 define('EPGC_ERRORS_NO_SELECTED_CALENDARS', __('No selected calendars', 'embedpress'));
23 define('EPGC_ERRORS_TOKEN_AND_API_KEY_MISSING', __('Access token and API key are missing.', 'embedpress'));
24 define('EPGC_TRANSIENT_PREFIX', 'pgc_ev_');
25 define('EPGC_ENQUEUE_ACTION_PRIORITY', 11);
26 define( 'EPGC_REDIRECT_URL', admin_url('admin.php?page=embedpress&page_type=google-calendar'));
27 }
28 if (!defined('EPGC_EVENTS_MAX_RESULTS')) {
29 define('EPGC_EVENTS_MAX_RESULTS', 250);
30 }
31
32 if (!defined('EPGC_EVENTS_DEFAULT_TITLE')) {
33 define('EPGC_EVENTS_DEFAULT_TITLE', '');
34 }
35
36
37 if (!defined('EPGC_ASSET_URL')) {
38 define('EPGC_ASSET_URL', plugin_dir_url(__FILE__) .'assets/');
39 }
40
41 class Embedpress_Google_Helper {
42
43 public static function print_calendar_list($calendarList = []) {
44 if ( empty( $calendarList) ) {
45 $calendarList = static::getDecoded( 'epgc_calendarlist' ); //settings_selected_calendar_ids_json_cb
46 }
47 if ( ! empty( $calendarList ) ) {
48 $selectedCalendarIds = get_option( 'epgc_selected_calendar_ids' ); // array
49 if ( empty( $selectedCalendarIds ) ) {
50 $selectedCalendarIds = [];
51 }
52 ?>
53 <ul>
54 <?php foreach ( $calendarList as $calendar ) { ?>
55 <?php
56 $calendarId = $calendar['id'];
57 $htmlId = md5( $calendarId );
58 ?>
59 <p class="epgc-calendar-filter">
60 <input id="<?php echo $htmlId; ?>" type="checkbox" name="epgc_selected_calendar_ids[]"
61 <?php if ( in_array( $calendarId, $selectedCalendarIds ) ) {
62 echo ' checked ';
63 } ?>
64 value="<?php echo esc_attr( $calendarId ); ?>"/>
65 <label for="<?php echo $htmlId; ?>">
66 <span class="epgc-calendar-color" style="background-color:<?php echo esc_attr( $calendar['backgroundColor'] ); ?>"></span>
67 <?php echo esc_html( $calendar['summary'] ); ?><?php if ( ! empty( $calendar['primary'] ) ) {
68 echo ' (primary)';
69 } ?>
70 </label>
71 <br>ID: <?php echo esc_html( $calendarId ); ?>
72 </p>
73 <?php } ?>
74 </ul>
75 <?php
76 $refreshToken = get_option( "epgc_refresh_token" );
77 if ( empty( $refreshToken ) ) {
78 static::show_notice( EPGC_ERRORS_REFRESH_TOKEN_MISSING, 'error', false );
79 }
80 } else {
81 ?>
82 <p><?php _e( 'No calendar was found.', 'embedpress' ); ?></p>
83 <?php
84 }
85 }
86
87 /**
88 * Helper function to return array from option (that should be a JSON string).
89 * @return array or $default = null
90 */
91 public static function getDecoded($optionName, $default = null) {
92 $item = get_option($optionName);
93 // $item should be a JSON string.
94 if (!empty($item)) {
95 return json_decode($item, true);
96 }
97 return $default;
98 }
99
100
101 public static function show_notice($notice, $type, $dismissable) {
102 ?>
103 <div class="notice notice-<?php echo esc_attr($type); echo $dismissable ? ' is-dismissible' : ''; ?>">
104 <p><?php echo $notice; ?></p>
105 </div>
106 <?php
107 }
108
109 public static function ajax_get_calendar() {
110
111 check_ajax_referer('epgc_nonce');
112
113 try {
114
115 if (empty($_POST['start']) || empty($_POST['end'])) {
116 throw new Exception(EPGC_ERRORS_INVALID_FORMAT);
117 }
118
119 // Start and end are in ISO8601 string format with timezone offset (e.g. 2018-09-01T12:30:00-05:00)
120 $start = $_POST['start'];
121 $end = $_POST['end'];
122
123 $thisCalendarids = [];
124 $postedCalendarIds = [];
125 if (array_key_exists('thisCalendarids', $_POST) && !empty($_POST['thisCalendarids'])) {
126 $postedCalendarIds = array_map('trim', explode(',', $_POST['thisCalendarids']));
127 }
128 $privateSettingsCalendarListIds = array_map(function($item) {
129 return $item['id'];
130 }, static::getDecoded('epgc_calendarlist', []));
131 if (!empty($privateSettingsCalendarListIds)) {
132 $privateSettingsSelectedCalendarListIds = get_option('epgc_selected_calendar_ids');
133 // if (empty($postedCalendarIds)) {
134 // // If we have private selected calendars in settings and we get NO selected calendars from widget, shortcode, Gutenberg block, this means
135 // // ALL private calendars will be used.
136 // $postedCalendarIds = $privateSettingsSelectedCalendarListIds;
137 // }
138 foreach ($postedCalendarIds as $calId) {
139 if (!in_array($calId, $privateSettingsCalendarListIds) || in_array($calId, $privateSettingsSelectedCalendarListIds)) {
140 $thisCalendarids[] = $calId;
141 }
142 }
143 } else {
144 $thisCalendarids = $postedCalendarIds;
145 }
146
147 $cacheTime = get_option('epgc_cache_time'); // empty == no cache!
148
149 // We can have mutiple calendars with different calendar selections,
150 // so key should be including calendar selection.
151 $transientKey = EPGC_TRANSIENT_PREFIX . $start . $end . md5(implode('-', $thisCalendarids));
152
153 $transientItems = !empty($cacheTime) ? get_transient($transientKey) : false;
154
155 $calendarListByKey = static::get_calendars_by_key($thisCalendarids);
156
157 if ($transientItems !== false) {
158 wp_send_json(['items' => $transientItems, 'calendars' => $calendarListByKey]);
159 wp_die();
160 }
161
162 $colorList = false; // false means not queried yet / otherwise [] or filled []
163
164 $results = [];
165
166 $optParams = array(
167 'maxResults' => EPGC_EVENTS_MAX_RESULTS,
168 'orderBy' => 'startTime',
169 'singleEvents' => 'true',
170 'timeMin' => $start,
171 'timeMax' => $end,
172 );
173 if (!empty($_POST['timeZone'])) {
174 $optParams['timeZone'] = $_POST['timeZone'];
175 }
176
177 $hasAccessToken = get_option('epgc_access_token');
178
179 if (!empty($hasAccessToken)) {
180
181 $client = static::getGoogleClient(true);
182 if ($client->isAccessTokenExpired()) {
183 if (!$client->getRefreshTOken()) {
184 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
185 }
186 $client->refreshAccessToken();
187 }
188 $service = new EmbedPress_GoogleCalendarClient($client);
189
190 foreach ($thisCalendarids as $calendarId) {
191 $results[$calendarId] = $service->getEvents($calendarId, $optParams);
192 }
193
194 } elseif (!empty(get_option('epgc_api_key'))) {
195
196 $referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
197 $apiKey = get_option('epgc_api_key');
198 $service = new EmbedPress_GoogleCalendarClient(null);
199 foreach ($thisCalendarids as $calendarId) {
200 $results[$calendarId] = $service->getEventsPublic($calendarId, $optParams, $apiKey, $referer);
201 }
202
203 } else {
204 // No API key and no OAuth2 token
205 throw new Exception(EPGC_ERRORS_TOKEN_AND_API_KEY_MISSING);
206 }
207
208 $items = [];
209 foreach ($results as $calendarId => $events) {
210 foreach ($events as $item) {
211 $newItem = [
212 'title' => empty($item['summary']) ? EPGC_EVENTS_DEFAULT_TITLE : $item['summary'],
213 'htmlLink' => $item['htmlLink'],
214 'description' => !empty($item['description']) ? $item['description'] : '',
215 'calId' => $calendarId,
216 'creator' => !empty($item['creator']) ? $item['creator'] : [],
217 'attendees' => !empty($item['attendees']) ? $item['attendees'] : [],
218 'attachments' => !empty($item['attachments']) ? $item['attachments'] : [],
219 'location' => !empty($item['location']) ? $item['location'] : ''
220 ];
221 if (!empty($item['start']['date'])) {
222 $newItem['allDay'] = true;
223 $newItem['start'] = $item['start']['date'];
224 $newItem['end'] = $item['end']['date'];
225 // $newItem['timeZone'] = $item['start']['timeZone']; // TODO? end timezone also exists...
226 } else {
227 $newItem['start'] = $item['start']['dateTime'];
228 $newItem['end'] = $item['end']['dateTime'];
229 // $newItem['timeZone'] = $item['start']['timeZone']; // TODO? end timezone also exists...
230 }
231 if (!empty($item['colorId'])) {
232 if ($colorList === false) {
233 $colorList = static::getDecoded('pgc_colorlist', []);
234 }
235 if (array_key_exists('event', $colorList) && array_key_exists($item['colorId'], $colorList['event'])) {
236 $newItem['bColor'] = $colorList['event'][$item['colorId']]['background'];
237 $newItem['fColor'] = $colorList['event'][$item['colorId']]['foreground'];
238 }
239 }
240
241 $items[] = $newItem;
242 }
243 }
244
245 if (!empty($cacheTime)) {
246 set_transient($transientKey, $items, $cacheTime * MINUTE_IN_SECONDS);
247 }
248
249 wp_send_json(['items' => $items, 'calendars' => $calendarListByKey]);
250 wp_die();
251 } catch (EmbedPress_GoogleClient_RequestException $ex) {
252 wp_send_json([
253 'error' => $ex->getMessage(),
254 'errorCode' => $ex->getCode(),
255 'errorDescription' => $ex->getDescription()]);
256 wp_die();
257 } catch (Exception $ex) {
258 wp_send_json([
259 'error' => $ex->getMessage(),
260 'errorCode' => $ex->getCode()]);
261 wp_die();
262 }
263 }
264
265 public static function get_calendars_by_key($calendarIds) {
266
267 $publicCalendarList = get_option('pgc_public_calendarlist');
268 if (empty($publicCalendarList)) {
269 $publicCalendarList = [];
270 }
271 $privateCalendarList = static::getDecoded('epgc_calendarlist', []);
272 if (empty($privateCalendarList)) {
273 $privateCalendarList = [];
274 }
275 $calendarList = $publicCalendarList + $privateCalendarList;
276 $keyedCalendarList = [];
277 foreach ($calendarList as $cal) {
278 $keyedCalendarList[$cal['id']] = $cal;
279 }
280
281 $calendarListByKey = [];
282 foreach ($calendarIds as $calId) {
283 $cal = array_key_exists($calId, $keyedCalendarList) ? $keyedCalendarList[$calId] : [
284 'summary' => $calId,
285 'backgroundColor' => 'rgb(121, 134, 203)'
286 ];
287 $calendarListByKey[$calId] = [
288 'summary' => $cal['summary'],
289 'backgroundColor' => $cal['backgroundColor']
290 ];
291 }
292
293 return $calendarListByKey;
294 }
295 /**
296 * Helper function that returns a valid Google Client.
297 * @return Embedpress_GoogleClient instance
298 * @param bool $withTokens If true, also get tokens.
299 * @throws Exception.
300 */
301 public static function getGoogleClient($withTokens = false) {
302
303 $authConfig = get_option('epgc_client_secret');
304 if (empty($authConfig)) {
305 throw new Exception(EPGC_ERRORS_CLIENT_SECRET_MISSING);
306 }
307 $authConfig = static::getDecoded('epgc_client_secret');
308 if (empty($authConfig)) {
309 throw new Exception(EPGC_ERRORS_CLIENT_SECRET_INVALID);
310 }
311
312 $c = new Embedpress_GoogleClient($authConfig);
313 $c->setScope('https://www.googleapis.com/auth/calendar.readonly');
314 if (!self::check_redirect_uri($authConfig)) {
315 throw new Exception(sprintf(EPGC_ERRORS_REDIRECT_URI_MISSING, EPGC_REDIRECT_URL));
316 }
317 $c->setRedirectUri(EPGC_REDIRECT_URL);
318 $c->setTokenCallback(function($accessTokenInfo, $refreshToken) {
319 update_option('epgc_access_token', json_encode($accessTokenInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), false);
320 if (!empty($refreshToken)) {
321 update_option('epgc_refresh_token', $refreshToken, false);
322 }
323 });
324
325 if ($withTokens) {
326 $accessToken = static::getDecoded('epgc_access_token');
327 if (empty($accessToken)) {
328 throw new Exception(EPGC_ERRORS_ACCESS_TOKEN_MISSING);
329 }
330 $c->setAccessTokenInfo($accessToken);
331 $refreshToken = get_option("epgc_refresh_token");
332 if (empty($refreshToken)) {
333 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
334 }
335 $c->setRefreshToken($refreshToken);
336 }
337
338 return $c;
339
340 }
341
342 /**
343 * Helper function to check if we have a valid redirect uri in the client secret.
344 * @return bool
345 */
346 public static function check_redirect_uri($decodedClientSecret) {
347 return !empty($decodedClientSecret)
348 && !empty($decodedClientSecret['web'])
349 && !empty($decodedClientSecret['web']['redirect_uris'])
350 && in_array(EPGC_REDIRECT_URL, $decodedClientSecret['web']['redirect_uris']);
351 }
352
353
354 /**
355 * Get a valid formatted client secret.
356 * @return array|false Secret Array, false if no exists, Exception for invalid one
357 **/
358 public static function get_valid_client_secret(&$error = '') {
359 $clientSecret = get_option('epgc_client_secret');
360 if (empty($clientSecret)) {
361 return false;
362 }
363 $clientSecret = static::getDecoded('epgc_client_secret');
364 if (empty($clientSecret)
365 || empty($clientSecret['web'])
366 || empty($clientSecret['web']['client_secret'])
367 || empty($clientSecret['web']['client_id']))
368 {
369 $error = EPGC_ERRORS_CLIENT_SECRET_INVALID;
370 } elseif (!self::check_redirect_uri($clientSecret))
371 {
372 $error = sprintf(EPGC_ERRORS_REDIRECT_URI_MISSING, admin_url('options-general.php?page=pgc'));
373 }
374 return $clientSecret;
375 }
376
377 public static function delete_calendar_cache() {
378 global $wpdb;
379 $wpdb->query("DELETE FROM " . $wpdb->options
380 . " WHERE option_name LIKE '_transient_timeout_" . EPGC_TRANSIENT_PREFIX . "%' OR option_name LIKE '_transient_" . EPGC_TRANSIENT_PREFIX . "%'");
381 }
382
383 /**
384 * Helper function to delete all plugin options.
385 */
386 public static function delete_options($which) { // which = all, public, private
387 if ($which === 'all' || $which === 'private') {
388 delete_option('epgc_access_token');
389 delete_option('epgc_refresh_token');
390 delete_option('epgc_selected_calendar_ids');
391 delete_option('epgc_calendarlist');
392 delete_option('epgc_client_secret');
393 }
394 if ($which === 'all' || $which === 'public') {
395 delete_option('epgc_api_key');
396 }
397 if ($which === 'all') {
398 delete_option('epgc_cache_time');
399 }
400 }
401
402 public static function uninstall() {
403 try {
404 $client = static::getGoogleClient();
405 $accessToken = static::getDecoded('epgc_access_token');
406 if (!empty($accessToken)) {
407 $client->setAccessTokenInfo($accessToken);
408 }
409 $refreshToken = get_option("epgc_refresh_token");
410 if (!empty($refreshToken)) {
411 $client->setRefreshToken($refreshToken);
412 }
413 if (empty($accessToken) && empty($refreshToken)) {
414 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
415 }
416 $client->revoke();
417 } catch (Exception $ex) {
418 // Too bad...
419 } finally {
420 // Clear all plugin data
421 static::delete_plugin_data();
422 }
423 }
424
425 /**
426 * Helper function to delete all plugin data.
427 */
428 public static function delete_plugin_data($which = 'all') {
429 self::delete_calendar_cache();
430 self::delete_options($which);
431 }
432 public static function removable_query_args($removable_query_args) {
433 $removable_query_args[] = 'epgcnotice';
434 return $removable_query_args;
435 }
436
437 public static function notices_init() {
438 if (!empty($_GET['epgcnotice'])) {
439 $epgcnotices = get_option('epgc_notices_' . get_current_user_id());
440 if (empty($epgcnotices)) {
441 return;
442 }
443 delete_option('epgc_notices_' . get_current_user_id());
444 add_action('admin_notices', function() use ($epgcnotices) {
445 foreach ($epgcnotices as $notice) {
446 ?>
447 <div class="notice notice-<?php echo esc_attr($notice['type']); ?> is-dismissible">
448 <p><?php echo $notice['content']; ?></p>
449 </div>
450 <?php
451 }
452 });
453 }
454 }
455
456 /**
457 * Helper function to add notice messages.
458 * @param bool $redirect Redirect if true.
459 */
460 public static function add_notice($content, $type = 'success', $redirect = false) {
461 $epgcnotices = get_option('epgc_notices_' . get_current_user_id());
462 if (empty($epgcnotices)) {
463 $epgcnotices = [];
464 }
465 $epgcnotices[] = [
466 'content' => $content,
467 'type' => $type
468 ];
469 update_option('epgc_notices_' . get_current_user_id(), $epgcnotices, false);
470 if ($redirect) {
471 wp_redirect(EPGC_REDIRECT_URL ."&epgcnotice=true");
472 }
473 }
474
475 /**
476 * Helper function die with different kind of errors.
477 */
478 public static function embedpress_die($error = null) {
479 $backLink = '<br><br><a href="' . admin_url('admin.php?page=embedpress&page_type=google-calendar') . '">' . __('Back', 'embedpress') . '</a>';
480 if (empty($error)) {
481 wp_die(__('Unknown error', 'embedpress') . $backLink);
482 }
483 if ($error instanceof Exception) {
484 $s = [];
485 if ($error->getCode()) {
486 $x[] = $error->getCode();
487 }
488 $s[] = $error->getMessage();
489 if ($error instanceof Embedpress_GoogleClient_RequestException) {
490 if ($error->getDescription()) {
491 $s[] = $error->getDescription();
492 }
493 }
494 wp_die(implode("<br>", $s) . $backLink);
495 } elseif (is_array($error)) {
496 wp_die(implode("<br>", $error) . $backLink);
497 } elseif (is_string($error)) {
498 wp_die($error . $backLink);
499 } else {
500 wp_die(__('Unknown error format', 'embedpress') . $backLink);
501 }
502 }
503
504 /**
505 * Helper function to return pretty printed JSON string.
506 * @return string
507 */
508 public static function getPrettyJSONString($jsonObject) {
509 return str_replace(" ", " ", json_encode($jsonObject, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
510 }
511
512 public static function sort_calendars(&$items) {
513 // Set locale to UTF-8 variant if this is not the case.
514 if (strpos(setlocale(LC_COLLATE, 0), '.UTF-8') === false) {
515 // If we set this to a non existing locale it will be the default locale after this call.
516 setlocale(LC_COLLATE, get_locale() . '.UTF-8');
517 }
518 usort($items, function($a, $b) {
519 return strcoll($a['summary'], $b['summary']);
520 });
521 }
522 public static function shortcode($atts = [], $content = null) {
523
524 // When we have no attributes, $atts is an empty string
525 if (!is_array($atts)) {
526 $atts = [];
527 }
528 wp_enqueue_style('dashicons');
529 wp_enqueue_style( 'fullcalendar');
530 wp_enqueue_style( 'fullcalendar_daygrid');
531 wp_enqueue_style( 'fullcalendar_timegrid');
532 wp_enqueue_style( 'fullcalendar_list');
533 wp_enqueue_style( 'epgc');
534 wp_enqueue_style( 'tippy_light');
535
536
537 wp_enqueue_script('popper');
538 wp_enqueue_script('tippy');
539 wp_enqueue_script('my_moment');
540 wp_enqueue_script('my_moment_timezone');
541 wp_enqueue_script('fullcalendar');
542 wp_enqueue_script('fullcalendar_moment');
543 wp_enqueue_script('fullcalendar_moment_timezone');
544 wp_enqueue_script('fullcalendar_daygrid');
545 wp_enqueue_script('fullcalendar_timegrid');
546 wp_enqueue_script('fullcalendar_list');
547 wp_enqueue_script('fullcalendar_locales');
548 wp_enqueue_script('epgc');
549 $defaultConfig = [
550 'header' => [
551 'left' => 'prev,next today',
552 'center' => 'title',
553 'right' => 'dayGridMonth,timeGridWeek,listWeek'
554 ]
555 ];
556 $userConfig = $defaultConfig; // copy
557 $userFilter = 'top';
558 $userEventPopup = 'true';
559 $userEventLink = 'true';
560 $userHidePassed = 'false';
561 $userHideFuture = 'false';
562 $userEventDescription = 'true';
563 $userEventLocation = 'true';
564 $userEventAttendees = 'false';
565 $userEventAttachments = 'false';
566 $userEventCreator = 'false';
567 $userEventCalendarname = 'false';
568 $calendarIds = '';
569 $uncheckedCalendarIds = ''; // in filter
570 // Get all non-fullcalendar known properties
571 foreach ($atts as $key => $value) {
572 if ($key === 'public') {
573 // This existsed in old versions, but we don't want it in our shortcode output, so skip it.
574 continue;
575 }
576 if ($key === 'filter') {
577 $userFilter = $value === 'true' ? 'top' : $value;
578 continue;
579 }
580 if ($key === 'eventpopup') {
581 $userEventPopup = $value;
582 continue;
583 }
584 if ($key === 'eventlink') {
585 $userEventLink = $value;
586 continue;
587 }
588 if ($key === 'hidepassed') {
589 $userHidePassed = $value;
590 continue;
591 }
592 if ($key === 'hidefuture') {
593 $userHideFuture = $value;
594 continue;
595 }
596 if ($key === 'eventdescription') {
597 $userEventDescription = $value;
598 continue;
599 }
600 if ($key === 'eventattachments') {
601 $userEventAttachments = $value;
602 continue;
603 }
604 if ($key === 'eventattendees') {
605 $userEventAttendees = $value;
606 continue;
607 }
608 if ($key === 'eventlocation') {
609 $userEventLocation = $value;
610 continue;
611 }
612 if ($key === 'eventcreator') {
613 $userEventCreator = $value;
614 continue;
615 }
616 if ($key === 'eventcalendarname') {
617 $userEventCalendarname = $value;
618 continue;
619 }
620 if ($key === 'uncheckedcalendarids' && !empty($value)) {
621 $uncheckedCalendarIds = $value; // comma separated string
622 continue;
623 }
624
625 if ($key === 'calendarids') {
626 if (!empty($value)) {
627 $calendarIds = $value; // comma separated string
628 }
629 continue;
630 }
631 if ($key === 'fullcalendarconfig') {
632 // A JSON string that we can directly send to FullCalendar
633 $userConfig = json_decode($value, true);
634 } else {
635 // Fullcalendar properties that get passed to fullCalendar instance.
636 $parts = explode('-', $key);
637 $partsCount = count($parts);
638 if ($partsCount > 1) {
639 $currentUserConfigLayer = &$userConfig;
640 for ($i = 0; $i < $partsCount; $i++) {
641 $part = $parts[$i];
642 if ($i + 1 === $partsCount) {
643 if ($value === 'true') {
644 $value = true;
645 } elseif ($value === 'false') {
646 $value = $value;
647 }
648 $currentUserConfigLayer[$part] = $value;
649 } else {
650 if (!array_key_exists($part, $currentUserConfigLayer)) {
651 $currentUserConfigLayer[$part] = [];
652 }
653 $currentUserConfigLayer = &$currentUserConfigLayer[$part];
654 }
655 }
656 } else {
657 $userConfig[$key] = $value;
658 }
659 }
660 }
661
662 $dataCalendarIds = '';
663 if (!empty($calendarIds)) {
664 $dataCalendarIds = 'data-calendarids=\'' . json_encode(array_map('trim', explode(',', $calendarIds))) . '\'';
665 } else {
666 $privateSettingsSelectedCalendarListIds = get_option('epgc_selected_calendar_ids', []);
667 if (!empty($privateSettingsSelectedCalendarListIds)) {
668 $dataCalendarIds = 'data-calendarids=\'' . json_encode($privateSettingsSelectedCalendarListIds) . '\'';
669 }
670 }
671
672 $dataUnchekedCalendarIds = '';
673 if (!empty($uncheckedCalendarIds)) {
674 $dataUnchekedCalendarIds = 'data-uncheckedcalendarids=\'' . json_encode(array_map('trim', explode(',', $uncheckedCalendarIds))) . '\'';
675 }
676
677 $filterHTML = '<div class="epgc-calendar-filter" ' . $dataUnchekedCalendarIds . '></div>';
678
679 return '<div class="epgc-calendar-wrapper epgc-calendar-page">' . ($userFilter === 'top' ? wp_kses_post($filterHTML) : '') . '<div '
680 . esc_attr($dataCalendarIds) . ' data-filter=\''
681 . esc_attr($userFilter) . '\' data-eventpopup=\''
682 . esc_attr($userEventPopup) . '\' data-eventlink=\''
683 . esc_attr($userEventLink) . '\' data-eventdescription=\''
684 . esc_attr($userEventDescription) . '\' data-eventlocation=\''
685 . esc_attr($userEventLocation) . '\' data-eventattachments=\''
686 . esc_attr($userEventAttachments) . '\' data-eventattendees=\''
687 . esc_attr($userEventAttendees) . '\' data-eventcreator=\''
688 . esc_attr($userEventCreator) . '\' data-eventcalendarname=\''
689 . esc_attr($userEventCalendarname) . '\' data-hidefuture=\''
690 . esc_attr($userHideFuture) . '\' data-hidepassed=\''
691 . esc_attr($userHidePassed) . '\' data-config=\''
692 . json_encode($userConfig) . '\' data-locale="'
693 . esc_attr(get_locale())
694 . '" class="epgc-calendar"></div>'
695 . ($userFilter === 'bottom' ? wp_kses_post($filterHTML) : '')
696 . '</div>';
697 }
698
699 public static function admin_post_calendarlist() {
700 try {
701 $client = static::getGoogleClient(true);
702 if ($client->isAccessTokenExpired()) {
703 if (!$client->getRefreshToken()) {
704 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
705 }
706 $client->refreshAccessToken();
707 }
708 $service = new Embedpress_GoogleCalendarClient($client);
709 $items = $service->getCalendarList();
710
711 self::sort_calendars($items);
712
713 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
714 self::add_notice(PGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS, 'success', true);
715 exit;
716 } catch (Exception $ex) {
717 self::embedpress_die($ex);
718 }
719 }
720 public static function admin_post_colorlist() {
721 try {
722 $client = static::getGoogleClient(true);
723 if ($client->isAccessTokenExpired()) {
724 if (!$client->getRefreshToken()) {
725 throw new Exception(PGC_ERRORS_REFRESH_TOKEN_MISSING);
726 }
727 $client->refreshAccessToken();
728 }
729 $service = new Embedpress_GoogleCalendarClient($client);
730 $items = $service->getColorList();
731 update_option('epgc_colorlist', self::getPrettyJSONString($items), false);
732 self::add_notice(EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS, 'success', true);
733 exit;
734 } catch (Exception $ex) {
735 self::embedpress_die($ex);
736 }
737 }
738 public static function admin_post_deletecache() {
739 if ( ! isset( $_POST['epgc_deletecache_data'] ) || ! wp_verify_nonce( $_POST['epgc_deletecache_data'], 'epgc_deletecache' ) || !current_user_can('manage_options')) {
740 print 'Sorry, your nonce did not verify.';
741 exit;
742 } else {
743 self::delete_calendar_cache();
744 self::add_notice(PGC_NOTICES_CACHE_DELETED, 'success', true);
745 exit;
746 }
747 }
748 public static function admin_post_verify() {
749 try {
750 $client = static::getGoogleClient(true);
751 $client->refreshAccessToken();
752 self::add_notice(PGC_NOTICES_VERIFY_SUCCESS, 'success', true);
753 exit;
754 } catch (Exception $ex) {
755 self::embedpress_die($ex);
756 }
757 }
758 public static function enqueue_scripts() {
759 wp_enqueue_style('dashicons');
760 wp_register_style('fullcalendar', EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.css', null, EMBEDPRESS_VERSION);
761 wp_register_style('fullcalendar_daygrid', EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
762 wp_register_style('fullcalendar_timegrid', EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.css', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION);
763 wp_register_style('fullcalendar_list', EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
764 wp_register_style('epgc', EPGC_ASSET_URL . 'css/epgc.css', ['fullcalendar_timegrid'], EMBEDPRESS_VERSION);
765 wp_register_style('tippy_light', EPGC_ASSET_URL . 'lib/tippy/light-border.css', null, EMBEDPRESS_VERSION);
766
767 //wp_enqueue_style( 'fullcalendar');
768 //wp_enqueue_style( 'fullcalendar_daygrid');
769 //wp_enqueue_style( 'fullcalendar_timegrid');
770 //wp_enqueue_style( 'fullcalendar_list');
771 //wp_enqueue_style( 'epgc');
772 //wp_enqueue_style( 'tippy_light');
773
774
775 wp_register_script('popper',EPGC_ASSET_URL . 'lib/popper.min.js', null, EMBEDPRESS_VERSION, true);
776 wp_register_script('tippy',EPGC_ASSET_URL . 'lib/tippy/tippy-bundle.umd.min.js', ['popper'], EMBEDPRESS_VERSION, true);
777 wp_register_script('my_moment',EPGC_ASSET_URL . 'lib/moment/moment-with-locales.min.js', null, EMBEDPRESS_VERSION, true);
778 wp_register_script('my_moment_timezone',EPGC_ASSET_URL . 'lib/moment/moment-timezone-with-data.min.js', ['my_moment'], EMBEDPRESS_VERSION, true);
779 wp_register_script('fullcalendar',EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.js', ['my_moment_timezone'], EMBEDPRESS_VERSION, true);
780 wp_register_script('fullcalendar_moment',EPGC_ASSET_URL . 'lib/fullcalendar4/moment/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
781 wp_register_script('fullcalendar_moment_timezone',EPGC_ASSET_URL . 'lib/fullcalendar4/moment-timezone/main.min.js', ['fullcalendar_moment'], EMBEDPRESS_VERSION, true);
782 wp_register_script('fullcalendar_daygrid',EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
783 wp_register_script('fullcalendar_timegrid',EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.js', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION, true);
784 wp_register_script('fullcalendar_list',EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
785 wp_register_script('fullcalendar_locales',EPGC_ASSET_URL . 'lib/fullcalendar4/core/locales-all.min.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
786 wp_register_script('epgc', EPGC_ASSET_URL . 'js/main.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
787
788 //wp_enqueue_script('popper');
789 //wp_enqueue_script('my_moment');
790 //wp_enqueue_script('my_moment_timezone');
791 //wp_enqueue_script('fullcalendar');
792 //wp_enqueue_script('fullcalendar_moment');
793 //wp_enqueue_script('fullcalendar_moment_timezone');
794 //wp_enqueue_script('fullcalendar_daygrid');
795 //wp_enqueue_script('fullcalendar_timegrid');
796 //wp_enqueue_script('fullcalendar_list');
797 //wp_enqueue_script('fullcalendar_locales');
798 //wp_enqueue_script('epgc');
799
800 $nonce = wp_create_nonce('epgc_nonce');
801 wp_localize_script('epgc', 'epgc_object', [
802 'ajax_url' => admin_url('admin-ajax.php'),
803 'nonce' => $nonce,
804 'trans' => [
805 'all_day' => __('All day', 'embedpress'),
806 'created_by' => __('Created by', 'embedpress'),
807 'go_to_event' => __('Go to event', 'embedpress'),
808 'unknown_error' => __('Unknown error', 'embedpress'),
809 'request_error' => __('Request error', 'embedpress'),
810 'loading' => __('Loading', 'embedpress')
811 ]
812 ]);
813
814 }
815
816 public static function remove_private_data() {
817 if ( ! isset( $_POST['epgc_remove_private_data'] ) || ! wp_verify_nonce( $_POST['epgc_remove_private_data'], 'epgc_remove_private' ) || !current_user_can('manage_options')) {
818 print 'Sorry, your nonce did not verify.';
819 exit;
820 } else {
821 self::delete_plugin_data('private');
822 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
823 exit;
824 }
825 }
826
827 public static function admin_post_remove() {
828
829 if ( ! isset( $_POST['epgc_remove_private_data'] ) || ! wp_verify_nonce( $_POST['epgc_remove_private_data'], 'epgc_remove_private' ) || !current_user_can('manage_options')) {
830 print 'Sorry, your nonce did not verify.';
831 exit;
832 } else {
833
834 self::delete_plugin_data();
835 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
836 exit;
837 }
838
839 }
840 public static function admin_post_revoke() {
841 try {
842 $client = self::getGoogleClient();
843 $accessToken = self::getDecoded('epgc_access_token');
844 if (!empty($accessToken)) {
845 $client->setAccessTokenInfo($accessToken);
846 }
847 $refreshToken = get_option("epgc_refresh_token");
848 if (!empty($refreshToken)) {
849 $client->setRefreshToken($refreshToken);
850 }
851 if (empty($accessToken) && empty($refreshToken)) {
852 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
853 }
854 $client->revoke();
855 // Clear access and refresh tokens
856 self::delete_plugin_data('private');
857 self::add_notice(EPGC_NOTICES_REVOKE_SUCCESS, 'success', true);
858 exit;
859 } catch (Exception $ex) {
860 self::embedpress_die($ex);
861 }
862 }
863 public static function admin_post_authorize() {
864 if ( ! isset( $_POST['epgc_authorize_data'] ) || ! wp_verify_nonce( $_POST['epgc_authorize_data'], 'epgc_authorize' ) || !current_user_can('manage_options')) {
865 print 'Sorry, your nonce did not verify.';
866 exit;
867 } else {
868 try {
869 $client = self::getGoogleClient();
870 $client->authorize();
871 exit;
872 } catch (Exception $ex) {
873 self::embedpress_die($ex);
874 }
875 }
876
877 }
878
879 public static function fetch_calendar() {
880 if ( empty( $_GET['page']) || 'embedpress' !== $_GET['page'] ) {
881 return;
882 }
883
884 if ( !current_user_can( 'manage_options') ) {
885 return;
886 }
887 if (!empty($_GET['code'])) {
888 // Redirect from Google authorize with code that we can use to get access and refresh tokens.
889 try {
890 $client = self::getGoogleClient();
891 // This will also set the access and refresh tokens on the client
892 // and call the token callback we have set to save them in the options table.
893 $client->handleCodeRedirect();
894 $service = new Embedpress_GoogleCalendarClient($client);
895 $items = $service->getCalendarList();
896 self::sort_calendars($items);
897
898 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
899 wp_redirect(EPGC_REDIRECT_URL);
900 exit;
901 } catch (Exception $ex) {
902 self::embedpress_die($ex);
903 }
904
905 }
906
907 $clientSecretError = '';
908 $clientSecret = self::get_valid_client_secret($clientSecretError);
909
910 $accessToken = self::getDecoded('epgc_access_token');
911
912 if (empty($clientSecret) || !empty($clientSecretError)) {
913 update_option('epgc_selected_calendar_ids', [], false);
914 }
915 if (!empty($accessToken)) {
916 // validate_selected_calendar_ids
917 }
918 if (empty($clientSecret) || !empty($clientSecretError)) {
919 // save new data from user input, show them input
920
921 } elseif (self::getDecoded('epgc_calendarlist')) {
922 // show calendar list
923 }
924
925 }
926 }
927
928
929
930
931
932
933 /**
934 * Add 'eepgcnotice' to the removable_query_args filter, so we can set this and
935 * WP will remove it for us. We use this for our custom admin notices. This way
936 * you can add parameters to the URL and check for them, but we won't see them
937 * in the URL.
938 */
939 add_filter('removable_query_args', [Embedpress_Google_Helper::class, 'removable_query_args']);
940
941 /**
942 * Check for 'epgcnotice' parameter and show admin notice if we have a option.
943 */
944 add_action('admin_init', [Embedpress_Google_Helper::class,'notices_init']);
945
946 /**
947 * Handle AJAX request from frontend.
948 */
949 add_action('wp_ajax_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
950 add_action('wp_ajax_nopriv_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
951
952 add_action('admin_post_epgc_calendarlist', [Embedpress_Google_Helper::class,'admin_post_calendarlist']);
953
954
955 add_action('admin_post_epgc_colorlist', [Embedpress_Google_Helper::class, 'admin_post_colorlist']);
956 add_action('admin_post_epgc_deletecache', [Embedpress_Google_Helper::class, 'admin_post_deletecache']);
957
958
959 /**
960 * Admin post action to verify if we have valid access and refresh token.
961 */
962 add_action('admin_post_epgc_verify', [Embedpress_Google_Helper::class, 'admin_post_verify']);
963
964 add_shortcode( 'embedpress_calendar', [Embedpress_Google_Helper::class, 'shortcode']);
965 add_action('wp_enqueue_scripts', [Embedpress_Google_Helper::class, 'enqueue_scripts'], EPGC_ENQUEUE_ACTION_PRIORITY);
966
967 add_action('admin_post_epgc_remove_private', [Embedpress_Google_Helper::class, 'remove_private_data']);
968
969 /**
970 * Admin post action to authorize access.
971 */
972 add_action('admin_post_epgc_authorize', [Embedpress_Google_Helper::class, 'admin_post_authorize']);
973
974 add_action('admin_init', [Embedpress_Google_Helper::class, 'fetch_calendar']);
975
976