PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 3.8.2
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v3.8.2
4.6.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 4 years ago GoogleClient.php 4 years ago
Embedpress_Google_Helper.php
946 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' ? $filterHTML : '') . '<div '
680 . $dataCalendarIds . ' data-filter=\'' . $userFilter . '\' data-eventpopup=\'' . $userEventPopup . '\' data-eventlink=\''
681 . $userEventLink . '\' data-eventdescription=\'' . $userEventDescription . '\' data-eventlocation=\''
682 . $userEventLocation . '\' data-eventattachments=\'' . $userEventAttachments . '\' data-eventattendees=\''
683 . $userEventAttendees . '\' data-eventcreator=\'' . $userEventCreator . '\' data-eventcalendarname=\''
684 . $userEventCalendarname . '\' data-hidefuture=\'' . $userHideFuture . '\' data-hidepassed=\''
685 . $userHidePassed . '\' data-config=\'' . json_encode($userConfig) . '\' data-locale="'
686 . get_locale() . '" class="epgc-calendar"></div>' . ($userFilter === 'bottom' ? $filterHTML : '') . '</div>';
687 }
688
689 public static function admin_post_calendarlist() {
690 try {
691 $client = static::getGoogleClient(true);
692 if ($client->isAccessTokenExpired()) {
693 if (!$client->getRefreshToken()) {
694 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
695 }
696 $client->refreshAccessToken();
697 }
698 $service = new Embedpress_GoogleCalendarClient($client);
699 $items = $service->getCalendarList();
700
701 self::sort_calendars($items);
702
703 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
704 self::add_notice(PGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS, 'success', true);
705 exit;
706 } catch (Exception $ex) {
707 self::embedpress_die($ex);
708 }
709 }
710 public static function admin_post_colorlist() {
711 try {
712 $client = static::getGoogleClient(true);
713 if ($client->isAccessTokenExpired()) {
714 if (!$client->getRefreshToken()) {
715 throw new Exception(PGC_ERRORS_REFRESH_TOKEN_MISSING);
716 }
717 $client->refreshAccessToken();
718 }
719 $service = new Embedpress_GoogleCalendarClient($client);
720 $items = $service->getColorList();
721 update_option('epgc_colorlist', self::getPrettyJSONString($items), false);
722 self::add_notice(EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS, 'success', true);
723 exit;
724 } catch (Exception $ex) {
725 self::embedpress_die($ex);
726 }
727 }
728 public static function admin_post_deletecache() {
729 self::delete_calendar_cache();
730 self::add_notice(PGC_NOTICES_CACHE_DELETED, 'success', true);
731 exit;
732 }
733 public static function admin_post_verify() {
734 try {
735 $client = static::getGoogleClient(true);
736 $client->refreshAccessToken();
737 self::add_notice(PGC_NOTICES_VERIFY_SUCCESS, 'success', true);
738 exit;
739 } catch (Exception $ex) {
740 self::embedpress_die($ex);
741 }
742 }
743 public static function enqueue_scripts() {
744 wp_enqueue_style('dashicons');
745 wp_register_style('fullcalendar', EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.css', null, EMBEDPRESS_VERSION);
746 wp_register_style('fullcalendar_daygrid', EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
747 wp_register_style('fullcalendar_timegrid', EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.css', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION);
748 wp_register_style('fullcalendar_list', EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
749 wp_register_style('epgc', EPGC_ASSET_URL . 'css/epgc.css', ['fullcalendar_timegrid'], EMBEDPRESS_VERSION);
750 wp_register_style('tippy_light', EPGC_ASSET_URL . 'lib/tippy/light-border.css', null, EMBEDPRESS_VERSION);
751
752 //wp_enqueue_style( 'fullcalendar');
753 //wp_enqueue_style( 'fullcalendar_daygrid');
754 //wp_enqueue_style( 'fullcalendar_timegrid');
755 //wp_enqueue_style( 'fullcalendar_list');
756 //wp_enqueue_style( 'epgc');
757 //wp_enqueue_style( 'tippy_light');
758
759
760 wp_register_script('popper',EPGC_ASSET_URL . 'lib/popper.min.js', null, EMBEDPRESS_VERSION, true);
761 wp_register_script('tippy',EPGC_ASSET_URL . 'lib/tippy/tippy-bundle.umd.min.js', ['popper'], EMBEDPRESS_VERSION, true);
762 wp_register_script('my_moment',EPGC_ASSET_URL . 'lib/moment/moment-with-locales.min.js', null, EMBEDPRESS_VERSION, true);
763 wp_register_script('my_moment_timezone',EPGC_ASSET_URL . 'lib/moment/moment-timezone-with-data.min.js', ['my_moment'], EMBEDPRESS_VERSION, true);
764 wp_register_script('fullcalendar',EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.js', ['my_moment_timezone'], EMBEDPRESS_VERSION, true);
765 wp_register_script('fullcalendar_moment',EPGC_ASSET_URL . 'lib/fullcalendar4/moment/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
766 wp_register_script('fullcalendar_moment_timezone',EPGC_ASSET_URL . 'lib/fullcalendar4/moment-timezone/main.min.js', ['fullcalendar_moment'], EMBEDPRESS_VERSION, true);
767 wp_register_script('fullcalendar_daygrid',EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
768 wp_register_script('fullcalendar_timegrid',EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.js', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION, true);
769 wp_register_script('fullcalendar_list',EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
770 wp_register_script('fullcalendar_locales',EPGC_ASSET_URL . 'lib/fullcalendar4/core/locales-all.min.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
771 wp_register_script('epgc', EPGC_ASSET_URL . 'js/main.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
772
773 //wp_enqueue_script('popper');
774 //wp_enqueue_script('my_moment');
775 //wp_enqueue_script('my_moment_timezone');
776 //wp_enqueue_script('fullcalendar');
777 //wp_enqueue_script('fullcalendar_moment');
778 //wp_enqueue_script('fullcalendar_moment_timezone');
779 //wp_enqueue_script('fullcalendar_daygrid');
780 //wp_enqueue_script('fullcalendar_timegrid');
781 //wp_enqueue_script('fullcalendar_list');
782 //wp_enqueue_script('fullcalendar_locales');
783 //wp_enqueue_script('epgc');
784
785 $nonce = wp_create_nonce('epgc_nonce');
786 wp_localize_script('epgc', 'epgc_object', [
787 'ajax_url' => admin_url('admin-ajax.php'),
788 'nonce' => $nonce,
789 'trans' => [
790 'all_day' => __('All day', 'embedpress'),
791 'created_by' => __('Created by', 'embedpress'),
792 'go_to_event' => __('Go to event', 'embedpress'),
793 'unknown_error' => __('Unknown error', 'embedpress'),
794 'request_error' => __('Request error', 'embedpress'),
795 'loading' => __('Loading', 'embedpress')
796 ]
797 ]);
798
799 }
800
801 public static function remove_private_data() {
802 self::delete_plugin_data('private');
803 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
804 exit;
805 }
806
807 public static function admin_post_remove() {
808 self::delete_plugin_data();
809 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
810 exit;
811 }
812 public static function admin_post_revoke() {
813 try {
814 $client = self::getGoogleClient();
815 $accessToken = self::getDecoded('epgc_access_token');
816 if (!empty($accessToken)) {
817 $client->setAccessTokenInfo($accessToken);
818 }
819 $refreshToken = get_option("epgc_refresh_token");
820 if (!empty($refreshToken)) {
821 $client->setRefreshToken($refreshToken);
822 }
823 if (empty($accessToken) && empty($refreshToken)) {
824 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
825 }
826 $client->revoke();
827 // Clear access and refresh tokens
828 self::delete_plugin_data('private');
829 self::add_notice(EPGC_NOTICES_REVOKE_SUCCESS, 'success', true);
830 exit;
831 } catch (Exception $ex) {
832 self::embedpress_die($ex);
833 }
834 }
835 public static function admin_post_authorize() {
836 try {
837 $client = self::getGoogleClient();
838 $client->authorize();
839 exit;
840 } catch (Exception $ex) {
841 self::embedpress_die($ex);
842 }
843 }
844
845 public static function fetch_calendar() {
846 if ( empty( $_GET['page']) || 'embedpress' !== $_GET['page'] ) {
847 return;
848 }
849
850 if ( !current_user_can( 'manage_options') ) {
851 return;
852 }
853 if (!empty($_GET['code'])) {
854 // Redirect from Google authorize with code that we can use to get access and refresh tokens.
855 try {
856 $client = self::getGoogleClient();
857 // This will also set the access and refresh tokens on the client
858 // and call the token callback we have set to save them in the options table.
859 $client->handleCodeRedirect();
860 $service = new Embedpress_GoogleCalendarClient($client);
861 $items = $service->getCalendarList();
862 self::sort_calendars($items);
863
864 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
865 wp_redirect(EPGC_REDIRECT_URL);
866 exit;
867 } catch (Exception $ex) {
868 self::embedpress_die($ex);
869 }
870
871 }
872
873 $clientSecretError = '';
874 $clientSecret = self::get_valid_client_secret($clientSecretError);
875
876 $accessToken = self::getDecoded('epgc_access_token');
877
878 if (empty($clientSecret) || !empty($clientSecretError)) {
879 update_option('epgc_client_secret', '', false);
880 update_option('epgc_selected_calendar_ids', [], false);
881 }
882 if (!empty($accessToken)) {
883 // validate_selected_calendar_ids
884 }
885 if (empty($clientSecret) || !empty($clientSecretError)) {
886 // save new data from user input, show them input
887
888 } elseif (self::getDecoded('epgc_calendarlist')) {
889 // show calendar list
890 }
891
892 }
893 }
894
895
896
897
898
899
900 /**
901 * Add 'eepgcnotice' to the removable_query_args filter, so we can set this and
902 * WP will remove it for us. We use this for our custom admin notices. This way
903 * you can add parameters to the URL and check for them, but we won't see them
904 * in the URL.
905 */
906 add_filter('removable_query_args', [Embedpress_Google_Helper::class, 'removable_query_args']);
907
908 /**
909 * Check for 'epgcnotice' parameter and show admin notice if we have a option.
910 */
911 add_action('admin_init', [Embedpress_Google_Helper::class,'notices_init']);
912
913 /**
914 * Handle AJAX request from frontend.
915 */
916 add_action('wp_ajax_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
917 add_action('wp_ajax_nopriv_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
918
919 add_action('admin_post_epgc_calendarlist', [Embedpress_Google_Helper::class,'admin_post_calendarlist']);
920
921
922 add_action('admin_post_epgc_colorlist', [Embedpress_Google_Helper::class, 'admin_post_colorlist']);
923 add_action('admin_post_epgc_deletecache', [Embedpress_Google_Helper::class, 'admin_post_deletecache']);
924 /**
925 * Admin post action to verify if we have valid access and refresh token.
926 */
927 add_action('admin_post_epgc_verify', [Embedpress_Google_Helper::class, 'admin_post_verify']);
928
929 add_shortcode( 'embedpress_calendar', [Embedpress_Google_Helper::class, 'shortcode']);
930 add_action('wp_enqueue_scripts', [Embedpress_Google_Helper::class, 'enqueue_scripts'], EPGC_ENQUEUE_ACTION_PRIORITY);
931
932 add_action('admin_post_epgc_remove_private', [Embedpress_Google_Helper::class, 'remove_private_data']);
933 /**
934 * Admin post action to delete all plugin data.
935 */
936 add_action('admin_post_epgc_remove', [Embedpress_Google_Helper::class,'admin_post_remove']);
937
938
939 /**
940 * Admin post action to authorize access.
941 */
942 add_action('admin_post_epgc_authorize', [Embedpress_Google_Helper::class, 'admin_post_authorize']);
943
944 add_action('admin_init', [Embedpress_Google_Helper::class, 'fetch_calendar']);
945
946