PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.0.5
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.0.5
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 2 years ago GoogleClient.php 4 years ago
Embedpress_Google_Helper.php
982 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 esc_html($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
529 foreach ($atts as &$value) {
530 $value = esc_attr($value);
531 }
532 unset($value); // Unset reference
533
534 wp_enqueue_style('dashicons');
535 wp_enqueue_style( 'fullcalendar');
536 wp_enqueue_style( 'fullcalendar_daygrid');
537 wp_enqueue_style( 'fullcalendar_timegrid');
538 wp_enqueue_style( 'fullcalendar_list');
539 wp_enqueue_style( 'epgc');
540 wp_enqueue_style( 'tippy_light');
541
542
543 wp_enqueue_script('popper');
544 wp_enqueue_script('tippy');
545 wp_enqueue_script('my_moment');
546 wp_enqueue_script('my_moment_timezone');
547 wp_enqueue_script('fullcalendar');
548 wp_enqueue_script('fullcalendar_moment');
549 wp_enqueue_script('fullcalendar_moment_timezone');
550 wp_enqueue_script('fullcalendar_daygrid');
551 wp_enqueue_script('fullcalendar_timegrid');
552 wp_enqueue_script('fullcalendar_list');
553 wp_enqueue_script('fullcalendar_locales');
554 wp_enqueue_script('epgc');
555 $defaultConfig = [
556 'header' => [
557 'left' => 'prev,next today',
558 'center' => 'title',
559 'right' => 'dayGridMonth,timeGridWeek,listWeek'
560 ]
561 ];
562 $userConfig = $defaultConfig; // copy
563 $userFilter = 'top';
564 $userEventPopup = 'true';
565 $userEventLink = 'true';
566 $userHidePassed = 'false';
567 $userHideFuture = 'false';
568 $userEventDescription = 'true';
569 $userEventLocation = 'true';
570 $userEventAttendees = 'false';
571 $userEventAttachments = 'false';
572 $userEventCreator = 'false';
573 $userEventCalendarname = 'false';
574 $calendarIds = '';
575 $uncheckedCalendarIds = ''; // in filter
576 // Get all non-fullcalendar known properties
577 foreach ($atts as $key => $value) {
578 if ($key === 'public') {
579 // This existsed in old versions, but we don't want it in our shortcode output, so skip it.
580 continue;
581 }
582 if ($key === 'filter') {
583 $userFilter = $value === 'true' ? 'top' : $value;
584 continue;
585 }
586 if ($key === 'eventpopup') {
587 $userEventPopup = $value;
588 continue;
589 }
590 if ($key === 'eventlink') {
591 $userEventLink = $value;
592 continue;
593 }
594 if ($key === 'hidepassed') {
595 $userHidePassed = $value;
596 continue;
597 }
598 if ($key === 'hidefuture') {
599 $userHideFuture = $value;
600 continue;
601 }
602 if ($key === 'eventdescription') {
603 $userEventDescription = $value;
604 continue;
605 }
606 if ($key === 'eventattachments') {
607 $userEventAttachments = $value;
608 continue;
609 }
610 if ($key === 'eventattendees') {
611 $userEventAttendees = $value;
612 continue;
613 }
614 if ($key === 'eventlocation') {
615 $userEventLocation = $value;
616 continue;
617 }
618 if ($key === 'eventcreator') {
619 $userEventCreator = $value;
620 continue;
621 }
622 if ($key === 'eventcalendarname') {
623 $userEventCalendarname = $value;
624 continue;
625 }
626 if ($key === 'uncheckedcalendarids' && !empty($value)) {
627 $uncheckedCalendarIds = $value; // comma separated string
628 continue;
629 }
630
631 if ($key === 'calendarids') {
632 if (!empty($value)) {
633 $calendarIds = $value; // comma separated string
634 }
635 continue;
636 }
637 if ($key === 'fullcalendarconfig') {
638 // A JSON string that we can directly send to FullCalendar
639 $userConfig = json_decode($value, true);
640 } else {
641 // Fullcalendar properties that get passed to fullCalendar instance.
642 $parts = explode('-', $key);
643 $partsCount = count($parts);
644 if ($partsCount > 1) {
645 $currentUserConfigLayer = &$userConfig;
646 for ($i = 0; $i < $partsCount; $i++) {
647 $part = $parts[$i];
648 if ($i + 1 === $partsCount) {
649 if ($value === 'true') {
650 $value = true;
651 } elseif ($value === 'false') {
652 $value = $value;
653 }
654 $currentUserConfigLayer[$part] = $value;
655 } else {
656 if (!array_key_exists($part, $currentUserConfigLayer)) {
657 $currentUserConfigLayer[$part] = [];
658 }
659 $currentUserConfigLayer = &$currentUserConfigLayer[$part];
660 }
661 }
662 } else {
663 $userConfig[$key] = $value;
664 }
665 }
666 }
667
668 $dataCalendarIds = '';
669 if (!empty($calendarIds)) {
670 $dataCalendarIds = 'data-calendarids=\'' . json_encode(array_map('trim', explode(',', $calendarIds))) . '\'';
671 } else {
672 $privateSettingsSelectedCalendarListIds = get_option('epgc_selected_calendar_ids', []);
673 if (!empty($privateSettingsSelectedCalendarListIds)) {
674 $dataCalendarIds = 'data-calendarids=\'' . json_encode($privateSettingsSelectedCalendarListIds) . '\'';
675 }
676 }
677
678 $dataUnchekedCalendarIds = '';
679 if (!empty($uncheckedCalendarIds)) {
680 $dataUnchekedCalendarIds = 'data-uncheckedcalendarids=\'' . json_encode(array_map('trim', explode(',', $uncheckedCalendarIds))) . '\'';
681 }
682
683 $filterHTML = '<div class="epgc-calendar-filter" ' . $dataUnchekedCalendarIds . '></div>';
684
685 return '<div class="epgc-calendar-wrapper epgc-calendar-page">' . ($userFilter === 'top' ? wp_kses_post($filterHTML) : '') . '<div '
686 . esc_attr($dataCalendarIds) . ' data-filter=\''
687 . esc_attr($userFilter) . '\' data-eventpopup=\''
688 . esc_attr($userEventPopup) . '\' data-eventlink=\''
689 . esc_attr($userEventLink) . '\' data-eventdescription=\''
690 . esc_attr($userEventDescription) . '\' data-eventlocation=\''
691 . esc_attr($userEventLocation) . '\' data-eventattachments=\''
692 . esc_attr($userEventAttachments) . '\' data-eventattendees=\''
693 . esc_attr($userEventAttendees) . '\' data-eventcreator=\''
694 . esc_attr($userEventCreator) . '\' data-eventcalendarname=\''
695 . esc_attr($userEventCalendarname) . '\' data-hidefuture=\''
696 . esc_attr($userHideFuture) . '\' data-hidepassed=\''
697 . esc_attr($userHidePassed) . '\' data-config=\''
698 . json_encode($userConfig) . '\' data-locale="'
699 . esc_attr(get_locale())
700 . '" class="epgc-calendar"></div>'
701 . ($userFilter === 'bottom' ? wp_kses_post($filterHTML) : '')
702 . '</div>';
703 }
704
705 public static function admin_post_calendarlist() {
706 try {
707 $client = static::getGoogleClient(true);
708 if ($client->isAccessTokenExpired()) {
709 if (!$client->getRefreshToken()) {
710 throw new Exception(EPGC_ERRORS_REFRESH_TOKEN_MISSING);
711 }
712 $client->refreshAccessToken();
713 }
714 $service = new Embedpress_GoogleCalendarClient($client);
715 $items = $service->getCalendarList();
716
717 self::sort_calendars($items);
718
719 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
720 self::add_notice(PGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS, 'success', true);
721 exit;
722 } catch (Exception $ex) {
723 self::embedpress_die($ex);
724 }
725 }
726 public static function admin_post_colorlist() {
727 try {
728 $client = static::getGoogleClient(true);
729 if ($client->isAccessTokenExpired()) {
730 if (!$client->getRefreshToken()) {
731 throw new Exception(PGC_ERRORS_REFRESH_TOKEN_MISSING);
732 }
733 $client->refreshAccessToken();
734 }
735 $service = new Embedpress_GoogleCalendarClient($client);
736 $items = $service->getColorList();
737 update_option('epgc_colorlist', self::getPrettyJSONString($items), false);
738 self::add_notice(EPGC_NOTICES_COLORLIST_UPDATE_SUCCESS, 'success', true);
739 exit;
740 } catch (Exception $ex) {
741 self::embedpress_die($ex);
742 }
743 }
744 public static function admin_post_deletecache() {
745 if ( ! isset( $_POST['epgc_deletecache_data'] ) || ! wp_verify_nonce( $_POST['epgc_deletecache_data'], 'epgc_deletecache' ) || !current_user_can('manage_options')) {
746 print 'Sorry, your nonce did not verify.';
747 exit;
748 } else {
749 self::delete_calendar_cache();
750 self::add_notice(PGC_NOTICES_CACHE_DELETED, 'success', true);
751 exit;
752 }
753 }
754 public static function admin_post_verify() {
755 try {
756 $client = static::getGoogleClient(true);
757 $client->refreshAccessToken();
758 self::add_notice(PGC_NOTICES_VERIFY_SUCCESS, 'success', true);
759 exit;
760 } catch (Exception $ex) {
761 self::embedpress_die($ex);
762 }
763 }
764 public static function enqueue_scripts() {
765 wp_enqueue_style('dashicons');
766 wp_register_style('fullcalendar', EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.css', null, EMBEDPRESS_VERSION);
767 wp_register_style('fullcalendar_daygrid', EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
768 wp_register_style('fullcalendar_timegrid', EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.css', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION);
769 wp_register_style('fullcalendar_list', EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.css', ['fullcalendar'], EMBEDPRESS_VERSION);
770 wp_register_style('epgc', EPGC_ASSET_URL . 'css/epgc.css', ['fullcalendar_timegrid'], EMBEDPRESS_VERSION);
771 wp_register_style('tippy_light', EPGC_ASSET_URL . 'lib/tippy/light-border.css', null, EMBEDPRESS_VERSION);
772
773 //wp_enqueue_style( 'fullcalendar');
774 //wp_enqueue_style( 'fullcalendar_daygrid');
775 //wp_enqueue_style( 'fullcalendar_timegrid');
776 //wp_enqueue_style( 'fullcalendar_list');
777 //wp_enqueue_style( 'epgc');
778 //wp_enqueue_style( 'tippy_light');
779
780
781 wp_register_script('popper',EPGC_ASSET_URL . 'lib/popper.min.js', null, EMBEDPRESS_VERSION, true);
782 wp_register_script('tippy',EPGC_ASSET_URL . 'lib/tippy/tippy-bundle.umd.min.js', ['popper'], EMBEDPRESS_VERSION, true);
783 wp_register_script('my_moment',EPGC_ASSET_URL . 'lib/moment/moment-with-locales.min.js', null, EMBEDPRESS_VERSION, true);
784 wp_register_script('my_moment_timezone',EPGC_ASSET_URL . 'lib/moment/moment-timezone-with-data.min.js', ['my_moment'], EMBEDPRESS_VERSION, true);
785 wp_register_script('fullcalendar',EPGC_ASSET_URL . 'lib/fullcalendar4/core/main.min.js', ['my_moment_timezone'], EMBEDPRESS_VERSION, true);
786 wp_register_script('fullcalendar_moment',EPGC_ASSET_URL . 'lib/fullcalendar4/moment/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
787 wp_register_script('fullcalendar_moment_timezone',EPGC_ASSET_URL . 'lib/fullcalendar4/moment-timezone/main.min.js', ['fullcalendar_moment'], EMBEDPRESS_VERSION, true);
788 wp_register_script('fullcalendar_daygrid',EPGC_ASSET_URL . 'lib/fullcalendar4/daygrid/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
789 wp_register_script('fullcalendar_timegrid',EPGC_ASSET_URL . 'lib/fullcalendar4/timegrid/main.min.js', ['fullcalendar_daygrid'], EMBEDPRESS_VERSION, true);
790 wp_register_script('fullcalendar_list',EPGC_ASSET_URL . 'lib/fullcalendar4/list/main.min.js', ['fullcalendar'], EMBEDPRESS_VERSION, true);
791 wp_register_script('fullcalendar_locales',EPGC_ASSET_URL . 'lib/fullcalendar4/core/locales-all.min.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
792 wp_register_script('epgc', EPGC_ASSET_URL . 'js/main.js',['fullcalendar'], EMBEDPRESS_VERSION, true);
793
794 //wp_enqueue_script('popper');
795 //wp_enqueue_script('my_moment');
796 //wp_enqueue_script('my_moment_timezone');
797 //wp_enqueue_script('fullcalendar');
798 //wp_enqueue_script('fullcalendar_moment');
799 //wp_enqueue_script('fullcalendar_moment_timezone');
800 //wp_enqueue_script('fullcalendar_daygrid');
801 //wp_enqueue_script('fullcalendar_timegrid');
802 //wp_enqueue_script('fullcalendar_list');
803 //wp_enqueue_script('fullcalendar_locales');
804 //wp_enqueue_script('epgc');
805
806 $nonce = wp_create_nonce('epgc_nonce');
807 wp_localize_script('epgc', 'epgc_object', [
808 'ajax_url' => admin_url('admin-ajax.php'),
809 'nonce' => $nonce,
810 'trans' => [
811 'all_day' => __('All day', 'embedpress'),
812 'created_by' => __('Created by', 'embedpress'),
813 'go_to_event' => __('Go to event', 'embedpress'),
814 'unknown_error' => __('Unknown error', 'embedpress'),
815 'request_error' => __('Request error', 'embedpress'),
816 'loading' => __('Loading', 'embedpress')
817 ]
818 ]);
819
820 }
821
822 public static function remove_private_data() {
823 if ( ! isset( $_POST['epgc_remove_private_data'] ) || ! wp_verify_nonce( $_POST['epgc_remove_private_data'], 'epgc_remove_private' ) || !current_user_can('manage_options')) {
824 print 'Sorry, your nonce did not verify.';
825 exit;
826 } else {
827 self::delete_plugin_data('private');
828 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
829 exit;
830 }
831 }
832
833 public static function admin_post_remove() {
834
835 if ( ! isset( $_POST['epgc_remove_private_data'] ) || ! wp_verify_nonce( $_POST['epgc_remove_private_data'], 'epgc_remove_private' ) || !current_user_can('manage_options')) {
836 print 'Sorry, your nonce did not verify.';
837 exit;
838 } else {
839
840 self::delete_plugin_data();
841 self::add_notice(EPGC_NOTICES_REMOVE_SUCCESS, 'success', true);
842 exit;
843 }
844
845 }
846 public static function admin_post_revoke() {
847 try {
848 $client = self::getGoogleClient();
849 $accessToken = self::getDecoded('epgc_access_token');
850 if (!empty($accessToken)) {
851 $client->setAccessTokenInfo($accessToken);
852 }
853 $refreshToken = get_option("epgc_refresh_token");
854 if (!empty($refreshToken)) {
855 $client->setRefreshToken($refreshToken);
856 }
857 if (empty($accessToken) && empty($refreshToken)) {
858 throw new Exception(EPGC_ERRORS_ACCESS_REFRESH_TOKEN_MISSING);
859 }
860 $client->revoke();
861 // Clear access and refresh tokens
862 self::delete_plugin_data('private');
863 self::add_notice(EPGC_NOTICES_REVOKE_SUCCESS, 'success', true);
864 exit;
865 } catch (Exception $ex) {
866 self::embedpress_die($ex);
867 }
868 }
869 public static function admin_post_authorize() {
870 if ( ! isset( $_POST['epgc_authorize_data'] ) || ! wp_verify_nonce( $_POST['epgc_authorize_data'], 'epgc_authorize' ) || !current_user_can('manage_options')) {
871 print 'Sorry, your nonce did not verify.';
872 exit;
873 } else {
874 try {
875 $client = self::getGoogleClient();
876 $client->authorize();
877 exit;
878 } catch (Exception $ex) {
879 self::embedpress_die($ex);
880 }
881 }
882
883 }
884
885 public static function fetch_calendar() {
886 if ( empty( $_GET['page']) || 'embedpress' !== $_GET['page'] ) {
887 return;
888 }
889
890 if ( !current_user_can( 'manage_options') ) {
891 return;
892 }
893 if (!empty($_GET['code'])) {
894 // Redirect from Google authorize with code that we can use to get access and refresh tokens.
895 try {
896 $client = self::getGoogleClient();
897 // This will also set the access and refresh tokens on the client
898 // and call the token callback we have set to save them in the options table.
899 $client->handleCodeRedirect();
900 $service = new Embedpress_GoogleCalendarClient($client);
901 $items = $service->getCalendarList();
902 self::sort_calendars($items);
903
904 update_option('epgc_calendarlist', self::getPrettyJSONString($items), false);
905 wp_redirect(EPGC_REDIRECT_URL);
906 exit;
907 } catch (Exception $ex) {
908 self::embedpress_die($ex);
909 }
910
911 }
912
913 $clientSecretError = '';
914 $clientSecret = self::get_valid_client_secret($clientSecretError);
915
916 $accessToken = self::getDecoded('epgc_access_token');
917
918 if (empty($clientSecret) || !empty($clientSecretError)) {
919 update_option('epgc_selected_calendar_ids', [], false);
920 }
921 if (!empty($accessToken)) {
922 // validate_selected_calendar_ids
923 }
924 if (empty($clientSecret) || !empty($clientSecretError)) {
925 // save new data from user input, show them input
926
927 } elseif (self::getDecoded('epgc_calendarlist')) {
928 // show calendar list
929 }
930
931 }
932 }
933
934
935
936
937
938
939 /**
940 * Add 'eepgcnotice' to the removable_query_args filter, so we can set this and
941 * WP will remove it for us. We use this for our custom admin notices. This way
942 * you can add parameters to the URL and check for them, but we won't see them
943 * in the URL.
944 */
945 add_filter('removable_query_args', [Embedpress_Google_Helper::class, 'removable_query_args']);
946
947 /**
948 * Check for 'epgcnotice' parameter and show admin notice if we have a option.
949 */
950 add_action('admin_init', [Embedpress_Google_Helper::class,'notices_init']);
951
952 /**
953 * Handle AJAX request from frontend.
954 */
955 add_action('wp_ajax_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
956 add_action('wp_ajax_nopriv_epgc_ajax_get_calendar', [Embedpress_Google_Helper::class, 'ajax_get_calendar']);
957
958 add_action('admin_post_epgc_calendarlist', [Embedpress_Google_Helper::class,'admin_post_calendarlist']);
959
960
961 add_action('admin_post_epgc_colorlist', [Embedpress_Google_Helper::class, 'admin_post_colorlist']);
962 add_action('admin_post_epgc_deletecache', [Embedpress_Google_Helper::class, 'admin_post_deletecache']);
963
964
965 /**
966 * Admin post action to verify if we have valid access and refresh token.
967 */
968 add_action('admin_post_epgc_verify', [Embedpress_Google_Helper::class, 'admin_post_verify']);
969
970 add_shortcode( 'embedpress_calendar', [Embedpress_Google_Helper::class, 'shortcode']);
971 add_action('wp_enqueue_scripts', [Embedpress_Google_Helper::class, 'enqueue_scripts'], EPGC_ENQUEUE_ACTION_PRIORITY);
972
973 add_action('admin_post_epgc_remove_private', [Embedpress_Google_Helper::class, 'remove_private_data']);
974
975 /**
976 * Admin post action to authorize access.
977 */
978 add_action('admin_post_epgc_authorize', [Embedpress_Google_Helper::class, 'admin_post_authorize']);
979
980 add_action('admin_init', [Embedpress_Google_Helper::class, 'fetch_calendar']);
981
982