michielvaneerd / privategooglecalendars

Private Google Calendars Wordpress plugin
https://michielvaneerd.github.io/privategooglecalendars/
8 stars 4 forks source link

Google calendar pgc_sort_calendars() items received as string, not an array #57

Open Metisek opened 1 month ago

Metisek commented 1 month ago

The current implementation of calendar list sorting and update has been enhanced to handle cases where the input $items may be provided as either a JSON string or a delimited string, which happens in when trying to refresh calendars from WP-admin. Debug log shows this traceback:

[30-Sep-2024 22:07:52 UTC] PHP Fatal error:  Uncaught TypeError: usort(): Argument #1 ($array) must be of type array, string given in /home/focuskff/domains/klubfocus.pl/public_html/wp-content/plugins/private-google-calendars/private-google-calendars.php:1002
Stack trace:
#0 /home/focuskff/domains/klubfocus.pl/public_html/wp-content/plugins/private-google-calendars/private-google-calendars.php(1002): usort()
#1 /home/focuskff/domains/klubfocus.pl/public_html/wp-content/plugins/private-google-calendars/private-google-calendars.php(1022): pgc_sort_calendars()
#2 /home/focuskff/domains/klubfocus.pl/public_html/wp-includes/class-wp-hook.php(324): pgc_admin_post_calendarlist()
#3 /home/focuskff/domains/klubfocus.pl/public_html/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()
#4 /home/focuskff/domains/klubfocus.pl/public_html/wp-includes/plugin.php(517): WP_Hook->do_action()
#5 /home/focuskff/domains/klubfocus.pl/public_html/wp-admin/admin-post.php(85): do_action()
#6 {main}
  thrown in /home/focuskff/domains/klubfocus.pl/public_html/wp-content/plugins/private-google-calendars/private-google-calendars.php on line 1002 

The following code has been adjusted to to this issue and this implementation works on my WP site:

function pgc_sort_calendars(&$items) 
{
  // Check if $items is a string and try to convert it to an array
  if (is_string($items)) {
    // Try to decode JSON string into an array
    $decodedItems = json_decode($items, true);
    if (json_last_error() === JSON_ERROR_NONE && is_array($decodedItems)) {
      $items = $decodedItems;
    } else {
      // If it's not JSON, assume it's a delimited string and split by comma
      $items = explode(",", $items);
    }
  }

  // Now proceed with sorting if $items is an array
  if (is_array($items)) {
    // Set locale to UTF-8 variant if this is not the case.
    if (strpos(setlocale(LC_COLLATE, 0), '.UTF-8') === false) {
      // Set locale to default with UTF-8
      setlocale(LC_COLLATE, get_locale() . '.UTF-8');
    }

    usort($items, function ($a, $b) {
      return strcoll($a['summary'], $b['summary']);
    });
  } else {
    throw new Exception('pgc_sort_calendars expects an array or string that can be converted into an array.');
  }
}

/**
 * Admin post action to update calendar list.
 */
add_action('admin_post_pgc_calendarlist', 'pgc_admin_post_calendarlist');
function pgc_admin_post_calendarlist()
{
  try {
    $client = getGoogleClient(true);
    if ($client->isAccessTokenExpired()) {
      if (!$client->getRefreshToken()) {
        throw new Exception(PGC_ERRORS_REFRESH_TOKEN_MISSING);
      }
      $client->refreshAccessToken();
    }
    $service = new PGC_GoogleCalendarClient($client);
    $items = $service->getCalendarList(PGC_CALENDARS_MAX_RESULTS);

    // Attempt to convert string to array if necessary
    if (is_string($items)) {
      $items = json_decode($items, true); // Or explode by delimiter if needed
    }

    pgc_sort_calendars($items);

    update_option('pgc_calendarlist', getPrettyJSONString($items), false);
    pgc_add_notice(PGC_NOTICES_CALENDARLIST_UPDATE_SUCCESS, 'success', true);
    exit;
  } catch (Exception $ex) {
    pgc_die($ex);
  }
}
michielvaneerd commented 3 weeks ago

Hi, thanks for your code. But when exactlt does this happen? You say "when trying to refresh calendars from WP-admin" - do you mean the "Update calendars" button on the Private Google Calendars settings page? When I click on this button, everything goes okay with the current implementation.

Metisek commented 3 weeks ago

Yes, I mean when i click "Update calendars" while fetching multiple calendars with OAuth. I've tried now to do it using your current implementation - the same problem occurs. Every calendar I have checked in attached image below is a private one. The problem didn't occur when I had only 1 private calendar, which I found interesting. image Error log is basically the same as the previous one I've sent.

michielvaneerd commented 1 week ago

I have looked into this by selecting only 2 private calendars on my site and then clicking the "Update calendars" button, and there it is working for me, so I'm not sure why you are experiencing this.

The pgc_sort_calendars call receives the $items parameter from the call to getCalendarList which calls doRequest from the PGC_GoogleClient_Request class. This doRequest calls json_decode on the result it receives from the Google API (see https://developers.google.com/calendar/api/v3/reference/events/list) and this cannot return a string. So I really don't understand how pgc_sort_calendars can receive a string in your case. All I can think of now is that another plugin interferes with this plugin, but I must admin that I don't know how.

It's not that I don't want to add your code to fix this, but I really want to first understand what is happening.

I understand that this doesn't happen when selecting just 1 private calendar. Does this also not happen when selecting 2 private calendars and also 1 or more public calendars?