stephenharris / Event-Organiser

WordPress plug-in, Event Organiser, development repository
http://wordpress.org/extend/plugins/event-organiser/
GNU General Public License v3.0
100 stars 76 forks source link

Full Calendar Shortcode - PHP Fatal error: Uncaught Exception: Error in formating DateTime object. #537

Open spa opened 1 year ago

spa commented 1 year ago

I'm receiving this error:

PHP Fatal error: Uncaught Exception: Error in formating DateTime object. Expected DateTime, but instead given boolean in /chroot/home/a031815c/tcotc.com/html/wp-content/plugins/event-organiser/includes/event-organiser-utility-functions.php:31

Plugin version: Version 3.12.3 PHP 7.4 WordPress 6.3 (but this was happening with the previous version as well)

Any ideas how to resolve this?

wunderdojo commented 1 year ago

Just ran into this too. PHP version 8.2. Literally just renewed my license thinking maybe I was missing an update but no luck.

stephenharris commented 1 year ago

This isn't a PHP/WordPress/Event Organiser version incompatibility. The event in question doesn't have any event dates associated. This can happen if you have event post types created by another plug-in. If you change the event's dates and save the event it should fix the issue, otherwise try deleting the event and recreating it.

wunderdojo commented 1 year ago

That's incorrect. Starting with a completely blank calendar, default 2023 theme, no other plugins installed and cacheing disabled I still run into the issue after correctly adding a single event. The issue is that the posts_fields filter in event-organiser-archives.php isn't getting applied so the query is returning an array of post objects without the eo_events custom fields (startDate, endDate, etc.)

wunderdojo commented 1 year ago

This is a super hacky work around but I have a lot of sites that have had their calendars down for a week now and needed to get something in place. Hopefully this helps the plugin author track down the actual issue with the pre_get_posts filters.

In event-organiser-event-functions.php at line 130 it uses get_posts() to get the events that match the current calendar view and filters. In event-organiser-archives.php it is adding filters inside of the pre_get_posts() filter. The pre_get_posts() filter gets called for any WP_Query (or wrapper function like get_posts() ) and allows you to modify the query before it is run. The author is using that to modify a few query vars, make sure the query applies to events, and if so then registers another handful of filters like __posts_fields__ -- which lets you modify the fields to return in the query. (_Note: you could simplify that by using postsclauses to just modify them in a single callback).

The issue for me is that while the posts_join, posts_where and other filters are being applied correctly, something is forcing the post fields to switch to just return the post IDs. Again, that's with a clean install, no other plugins running, default theme, etc. So then you get the fatal error because it's expecting start and end date fields.

I can see the posts_fields getting set up correctly inside __eventorganiser_pre_get_posts()__ so my temporary workaround was to simply declare a global variable right before that function:

global $eventQuery;

function eventorganiser_pre_get_posts( $query ) {

Then after the posts filters run at the end of the function I simply catch the clauses, build the SQL query and assign it to the global variable.

//Add the posts_* filters to modify the query
add_filter('posts_fields', 'eventorganiser_event_fields',10,2);
add_filter('posts_join', 'eventorganiser_join_tables',10,2);
add_filter('posts_where','eventorganiser_events_where',10,2);
add_filter('posts_orderby','eventorganiser_sort_events',10,2);
add_filter('posts_groupby', 'eventorganiser_event_groupby',10,2);

add_filter( 'posts_clauses', function( $clauses, $query ){

    global $wpdb, $eventQuery;

    $eventQuery = "SELECT " . $clauses['fields'] . " FROM {$wpdb->prefix}posts" . $clauses['from'] . $clauses['join'] . " WHERE 1=1" . $clauses['where'] . " ORDER BY " . $clauses['orderby'] . " " . $clauses['limits'];

    return $clauses;

  }, 10, 2 );

Finally, replace the get_posts() call with the following. The WP_Query call is what triggers the post_filters to get applied and the global variable to be set. Then I just directly call the query.

$setupQuery = new WP_Query( $query_array );
global $wpdb, $eventQuery;
$events = $wpdb->get_results( $eventQuery );
return $events;

Obviously far from ideal as it means double calls and the query isn't cached natively (it will be if you're using Redis or similar), but it's at least a short term fix for anyone else stuck on this.