%PDF- %PDF-
Direktori : /home/eirtvhdf/makkitrust.org/wp-content/plugins/the-events-calendar/src/Tribe/Template/ |
Current File : //home/eirtvhdf/makkitrust.org/wp-content/plugins/the-events-calendar/src/Tribe/Template/Month.php |
<?php /** * @for Calendar Template * This file contains the hook logic required to create an effective calendar month view. * * @package TribeEventsCalendar * */ if ( ! defined( 'ABSPATH' ) ) { die( '-1' ); } if ( ! class_exists( 'Tribe__Events__Template__Month' ) ) { /** * Month view template class */ class Tribe__Events__Template__Month extends Tribe__Events__Template_Factory { /** * Month Type Masks */ const PREVIOUS_MONTH = - 1; const CURRENT_MONTH = 0; const NEXT_MONTH = 1; /** * Prefix for month view ajax actions */ const AJAX_HOOK = 'tribe_calendar'; /** * The path to the template file used for the view. * This value is used in Shortcodes/Tribe_Events.php to * locate the correct template file for each shortcode * view. * * @var string */ public $view_path = 'month/content'; /** * Number of events per day * @var int * @see tribe_events_month_day_limit */ private $events_per_day; /** * Grid day events * @var array */ private $event_ids_by_day; /** * Array of days of the month * @var array */ private static $calendar_days = []; /** * Internal pointer to current day in the month view loop * @var int */ private static $current_day = - 1; /** * Internal pointer to current week in the month view loop * @var int */ private static $current_week = - 1; /** * Query args * @var array|null */ protected $args; /** * Indicates the array index marking the first entry for the current month. * @var int */ protected $current_month_begins; /** * Indicates the array index marking the last entry for the current month. * @var int */ protected $current_month_ends; /** * CSS class for the month view wrapper * @var string */ protected $body_class = 'events-gridview'; /** * Excerpt length on month view tooltips * @var int */ protected $excerpt_length = 30; /** * Static asset packages required for month view functionality * @var array */ protected $asset_packages = []; /** * HTML cache holder * @var Tribe__Template_Part_Cache */ private $html_cache; /** * Number of seconds before the month view cache (when enabled) should be * invalidated. * * @var int */ private $cache_expiration; /** * Whether the HTML cache is enabled * @var boolean */ private $use_cache; /** * The events in this month * @var */ private $events_in_month; /** * The category being viewed on month view * @var */ private $queried_event_cats; /** * The month date that was requested * @var string */ private $requested_date; /** * The first date to show on the calendar grid (may be in the previous month) * @var bool|string */ private $first_grid_date; /** * The last date to show on the calendar grid (may be in the next month) * @var bool|string */ private $final_grid_date; /** * Set the notices used on month view. * * @param array $args Set of $wp_query params for the month view, if none passed then will default to $wp_query. */ public function __construct( $args = [] ) { // set the proper query args $this->set_args( $args ); // include child categories in the query, save categories for reuse $this->set_queried_event_cats(); /** * Controls whether or not month view caching is enabled. * * Filtering this value can be useful if you need to implement * a fine grained caching policy for month view. * * @param boolean $enable * @param array $args */ $this->use_cache = apply_filters( 'tribe_events_enable_month_view_cache', $this->should_enable_month_view_cache(), $this->args ); // Cache the result of month/content.php if ( $this->use_cache ) { $this->cache_expiration = apply_filters( 'tribe_events_month_view_transient_expiration', HOUR_IN_SECONDS ); $cache_id = serialize( $this->args ); if ( isset( $_REQUEST ) && is_array( $_REQUEST ) ) { $cache_id .= serialize( $_REQUEST ); } $cache_id = md5( $cache_id ); $this->html_cache = new Tribe__Template_Part_Cache( 'month/content.php', $cache_id, $this->cache_expiration, 'save_post' ); } $this->events_per_day = apply_filters( 'tribe_events_month_day_limit', tribe_get_option( 'monthEventAmount', '3' ) ); $this->requested_date = $this->requested_date(); $this->first_grid_date = self::calculate_first_cell_date( $this->requested_date ); $this->final_grid_date = self::calculate_final_cell_date( $this->requested_date ); // get all the ids for the events in this month, speeds up queries $this->set_events_in_month(); // don't enqueue scripts and js when we're not constructing month view, // they'll have to be enqueued separately if ( ! tribe_is_month() ) { $this->asset_packages = []; } parent::__construct(); } /** * Indicates if month view cache should be enabled or not. * * If the month view cache setting itself is not enabled (or not set) then this * method will always return false. * * In other cases, the default rules are to cache everything in the 2 months past * to 12 months in the future range. This policy can be refined or replaced via * the 'tribe_events_enable_month_view_cache' filter hook. * * @return bool */ protected function should_enable_month_view_cache() { // Respect the month view caching setting if ( ! tribe_get_option( 'enable_month_view_cache', true ) ) { return false; } // Default to always caching the current month if ( ! isset( $this->args['eventDate'] ) ) { return true; } // If the eventDate argument is not in the expected format then do not cache if ( ! preg_match( '/^[0-9]{4}-[0-9]{1,2}$/', $this->args['eventDate'] ) ) { return false; } // If the requested month is more than 2 months in the past, do not cache if ( $this->args['eventDate'] < date_i18n( 'Y-m', Tribe__Date_Utils::wp_strtotime( '-2 months' ) ) ) { return false; } // If the requested month is more than 1yr in the future, do not cache if ( $this->args['eventDate'] > date_i18n( 'Y-m', Tribe__Date_Utils::wp_strtotime( '+1 year' ) ) ) { return false; } // In all other cases, let's cache it! return true; } /** * Returns an array containing the IDs of all the events in the month. * * @return array */ public function get_events_in_month_ids() { return $this->has_events() ? wp_list_pluck( $this->events_in_month, 'ID' ) : []; } /** * Add any special hooks for this view * any actions added here should also be removed in the unhook function * */ protected function hooks() { parent::hooks(); tribe_asset_enqueue( 'the-events-calendar' ); // Since we set is_post_type_archive to true on month view, this prevents 'Events' from being added to the page title add_filter( 'post_type_archive_title', '__return_false', 10 ); if ( ! empty( $this->events_in_month ) ) { add_filter( 'tribe_events_month_has_events', [ $this, 'has_events' ] ); } // Print JSON-LD markup on the `wp_head` add_action( 'wp_head', [ $this, 'json_ld_markup' ] ); } /** * When dealing with a place that has multiple events, we need to pass all the events as the first param * to allow the class to echo the correct JSON-LD script * * @return void */ public function json_ld_markup() { if ( ! $this->use_cache ) { $this->produce_json_ld_markup( true ); return; } $cache = new Tribe__Cache(); $prefix = 'events_month_jsonld'; if ( tribe_is_event_category() ) { $prefix = sprintf( 'events_cat_%d_month_jsonld', get_queried_object_id() ); } $cache_key = $this->get_month_view_cache_key( $prefix ); $json_ld = $cache->get_transient( $cache_key, 'save_post' ); if ( ! $json_ld ) { $json_ld = $this->produce_json_ld_markup(); $cache->set_transient( $cache_key, $json_ld, $this->cache_expiration, 'save_post' ); } echo $json_ld; } /** * Renders or returns the JSON LD markup. * * @param bool $echo * * @return string */ protected function produce_json_ld_markup( $echo = false ) { if ( ! $echo ) { ob_start(); } $events = wp_list_pluck( $this->events_in_month, 'ID' ); if ( tribe_is_event_category() ) { $events = $this->filter_by_current_term( $events ); } Tribe__Events__JSON_LD__Event::instance()->markup( $events ); if ( ! $echo ) { return ob_get_clean(); } } /** * Remove any event that is not the same as the current term of the array of events, it return a modified events * array with the events that only has the current term or original events if the term is not valid. * * @since 4.6.9 * * @param array * * @return array */ private function filter_by_current_term( $events ) { $taxonomy = get_query_var( 'taxonomy' ); $current_term = get_term_by( 'id', get_queried_object_id(), $taxonomy ); // get_term_by returns false if term does not exists or on failure. if ( false === $current_term ) { return $events; } foreach ( (array) $events as $key => $event_id ) { if ( ! has_term( $current_term->term_id, $taxonomy, $event_id ) ) { unset( $events[ $key ] ); } } return $events; } /** * Unhook all the hooks set up on this view * */ protected function unhook() { parent::unhook(); remove_filter( 'post_type_archive_title', '__return_false', 10 ); if ( ! empty( $this->events_in_month ) ) { remove_filter( 'tribe_events_month_has_events', [ $this, 'has_events' ] ); } remove_action( 'wp_head', [ $this, 'json_ld_markup' ] ); } /** * Set the correct args using either passed args, ajax request, or wp_query * * * @param array $args */ protected function set_args( $args = [] ) { $doing_ajax = ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ? true : false; if ( empty( $args ) && $doing_ajax ) { $post_status = [ 'publish' ]; if ( is_user_logged_in() ) { $post_status[] = 'private'; } // set the global query var for eventDisplay $args = [ 'post_type' => Tribe__Events__Main::POSTTYPE, 'eventDisplay' => 'month', 'eventDate' => is_array( $_POST['eventDate'] ) ? Tribe__Utils__Array::get( $_POST, [ 'eventDate', 0 ] ) : $_POST['eventDate'], 'post_status' => $post_status, ]; } if ( empty( $args ) ) { // if no args were passed to the constructor, get them from $wp_query if ( ! $wp_query = tribe_get_global_query_object() ) { return; } $args = $wp_query->query; if ( ! empty( $wp_query->query_vars['meta_query'] ) ) { $args['meta_query'] = $wp_query->query_vars['meta_query']; } } $this->args = $args; } /** * Set the notices used on month view * */ public function set_notices() { // Our focus is on the current month, not the complete range of events included in the current month view // (which may include some leading/trailing days of the next and previous months) $slice_length = $this->current_month_ends - $this->current_month_begins + 1; $current_month_counts = array_slice( self::$calendar_days, $this->current_month_begins, $slice_length ); foreach ( $current_month_counts as $day ) { if ( $day['events']->have_posts() ) { // some events were found, no need to continue return; } } // if we got this far, it means no events were found $this->nothing_found_notice(); } /** * Sets an appropriate no results found message. * */ protected function nothing_found_notice() { if ( ! empty( $this->args['suppress_nothing_found_notice'] ) ) { return; } $events_label_plural_lowercase = tribe_get_event_label_plural_lowercase(); list( $search_term, $tax_term, $geographic_term ) = $this->get_search_terms(); if ( ! empty( $search_term ) ) { Tribe__Notices::set_notice( 'event-search-no-results', sprintf( esc_html__( 'There were no results found for %s this month.', 'the-events-calendar' ), '<strong>"' . esc_html( urldecode( stripslashes( $search_term ) ) ) . '"</strong>' ) ); } // if attempting to view a category archive. elseif ( ! empty( $tax_term ) ) { Tribe__Notices::set_notice( 'events-not-found', sprintf( esc_html__( 'No matching %1$s listed under %2$s. Please try viewing the full calendar for a complete list of events.', 'the-events-calendar' ), $events_label_plural_lowercase, $tax_term ) ); } else { Tribe__Notices::set_notice( 'event-search-no-results', esc_html__( 'There were no results found.', 'the-events-calendar' ) ); } } /** * Get the title for month view * * @param string $original_title * @param string $sep * * @return string */ protected function get_title( $original_title, $sep = null ) { $new_title = parent::get_title( $original_title, $sep ); if ( get_query_var( 'eventDate' ) && has_filter( 'tribe_month_grid_view_title' ) ) { _deprecated_function( "The 'tribe_month_grid_view_title' filter", '3.8', " the 'tribe_get_events_title' filter" ); $title_date = date_i18n( tribe_get_date_option( 'monthAndYearFormat', 'F Y' ), strtotime( get_query_var( 'eventDate' ) ) ); $new_title = apply_filters( 'tribe_month_grid_view_title', $new_title, $sep, $title_date ); } elseif ( has_filter( 'tribe_events_this_month_title' ) ) { _deprecated_function( "The 'tribe_events_this_month_title' filter", '3.8', " the 'tribe_get_events_title' filter" ); $new_title = apply_filters( 'tribe_events_this_month_title', $new_title, $sep ); } return $new_title; } /** * Get the view more link * * @param integer $date * * @return string */ private static function view_more_link( $date ) { $day_link = tribe_get_day_link( $date ); $tribe_bar_args = self::get_tribe_bar_args(); if ( ! empty( $tribe_bar_args ) ) { unset( $tribe_bar_args['tribe_event_display'] ); $day_link = add_query_arg( $tribe_bar_args, $day_link ); } return esc_url_raw( $day_link ); } /** * Set the queried terms as a class property * Include child categories of the category currently being viewed */ protected function set_queried_event_cats() { // Check the request for tribe_event_category if ( ! empty( $_POST['tribe_event_category'] ) ) { $this->args[ Tribe__Events__Main::TAXONOMY ] = $_POST['tribe_event_category']; } elseif ( ! empty( $_GET['tribe_event_category'] ) ) { $this->args[ Tribe__Events__Main::TAXONOMY ] = $_GET['tribe_event_category']; } $terms = []; $term_id = isset( $this->args[ Tribe__Events__Main::TAXONOMY ] ) ? $this->args[ Tribe__Events__Main::TAXONOMY ] : null; // get the term by id if it's an int if ( is_int( $term_id ) ) { $terms[0] = $term_id; } elseif ( is_string( $term_id ) ) { // get the term by slug if it's a string $term = get_term_by( 'slug', $term_id, Tribe__Events__Main::TAXONOMY ); if ( ! ( is_wp_error( $term ) || empty( $term ) ) ) { $terms[0] = $term->term_id; } } // make sure child terms are included if ( ! empty( $terms ) ) { $term_children = get_term_children( $terms[0], Tribe__Events__Main::TAXONOMY ); if ( is_array( $term_children ) ) { $terms = array_merge( $terms, $term_children ); } } $this->queried_event_cats = $terms; } /** * Get all the events in the month by directly querying the postmeta table * Also caches the postmeta and terms for the found events */ protected function set_events_in_month() { global $wpdb; $cache = new Tribe__Cache(); $cache_key = $this->get_month_view_cache_key( 'events_in_month' ); // We always use the object cache if available $cache_getter = 'get'; $cache_setter = 'set'; $expiration = 0; // If the site owner has explicitly enabled month view caching however let's use // transients instead, to guarantee persistence if ( $this->use_cache ) { $cache_getter = 'get_transient'; $cache_setter = 'set_transient'; $expiration = $this->cache_expiration; } // If we have a cached result, use that $cached_events = $cache->$cache_getter( $cache_key, 'save_post' ); if ( $cached_events !== false ) { /** * A simple utility to listen for when events have been successfully pulled from cache. * * @since 4.7.1 * * @param array $cached_events The array of event data pulled from cache. */ do_action( 'tribe_events_set_month_view_events_from_cache', $cached_events ); $this->events_in_month = $cached_events; return; } $post_stati = [ 'publish' ]; if ( is_user_logged_in() ) { $post_stati[] = 'private'; } $post_stati = implode( "','", $post_stati ); $ignore_hidden_events_AND = $this->hidden_events_fragment(); $start_date = tribe_beginning_of_day( $this->first_grid_date ); $end_date = tribe_end_of_day( $this->final_grid_date ); /** * Allow bypassing the events in month SQL query to return events an alternative way. * * @param null|array $events_in_month An array of events in month (default null, run the SQL query like normal) * @param string $start_date The start date to filter the queried events by * @param string $end_date The end date to filter the queried events by * * @since 4.5.9 */ $events_in_month = apply_filters( 'tribe_events_month_get_events_in_month', null, $start_date, $end_date ); if ( null === $events_in_month ) { $use_utc = Tribe__Timezones::is_mode( 'site' ); $start_date_key = $use_utc ? '_EventStartDateUTC' : '_EventStartDate'; $start_date_sql = esc_sql( $start_date ); $end_date_sql = esc_sql( $end_date ); $events_request = "SELECT tribe_event_start.post_id as ID, tribe_event_start.meta_value as EventStartDate, tribe_event_end_date.meta_value as EventEndDate FROM $wpdb->postmeta AS tribe_event_start LEFT JOIN $wpdb->posts ON tribe_event_start.post_id = $wpdb->posts.ID LEFT JOIN $wpdb->postmeta as tribe_event_end_date ON ( tribe_event_start.post_id = tribe_event_end_date.post_id AND tribe_event_end_date.meta_key = '_EventEndDate' ) WHERE $ignore_hidden_events_AND tribe_event_start.meta_key = '{$start_date_key}' AND ( ( tribe_event_start.meta_value >= '{$start_date_sql}' AND tribe_event_start.meta_value <= '{$end_date_sql}' ) OR ( tribe_event_end_date.meta_value >= '{$start_date_sql}' AND tribe_event_end_date.meta_value <= '{$end_date_sql}' ) OR ( tribe_event_start.meta_value < '{$start_date_sql}' AND tribe_event_end_date.meta_value > '{$end_date_sql}' ) ) AND $wpdb->posts.post_status IN('$post_stati') ORDER BY $wpdb->posts.menu_order ASC, DATE(tribe_event_start.meta_value) ASC, TIME(tribe_event_start.meta_value) ASC; "; $events_in_month = $wpdb->get_results( $events_request ); } $this->events_in_month = $events_in_month; // cache the postmeta and terms for all these posts in one go $event_ids_in_month = wp_list_pluck( $this->events_in_month, 'ID' ); update_object_term_cache( $event_ids_in_month, Tribe__Events__Main::POSTTYPE ); update_postmeta_cache( $event_ids_in_month ); // cache the found events in the object cache $cache->$cache_setter( $cache_key, $this->events_in_month, $expiration, 'save_post' ); } /** * Returns a string that can be used as a cache key for the current month. * * @param string $prefix * * @return string */ protected function get_month_view_cache_key( $prefix ) { $grid_start_datetime = tribe_beginning_of_day( $this->first_grid_date ); $grid_end_datetime = tribe_end_of_day( $this->final_grid_date ); return $prefix . '-' . $grid_start_datetime . '-' . $grid_end_datetime; } /** * Returns a posts-not-in SQL fragment for use in a WHERE clause or else an empty * string if it is unneeded. * * @return string */ protected function hidden_events_fragment() { global $wpdb; // Despite the method name, this obtains a list of post IDs to be hidden from *all* event listings $ignore_events = Tribe__Events__Query::getHideFromUpcomingEvents(); // If it is empty we don't need to do anything further if ( empty( $ignore_events ) ) { return ''; } // Let's ensure they are all absolute integers then collapse into a string $ignore_events = implode( ',', array_map( 'absint', $ignore_events ) ); // Terminate with AND so it can easily be combined with the rest of the WHERE clause return " $wpdb->posts.ID NOT IN ( $ignore_events ) AND "; } /** * Retrieves beginning/end times for a given date * * @param string $date Y-m-d date string * @param string $key Key of cached data to retrieve * * return string|int */ private function get_cutoff_details( $date, $key ) { static $beginnings_and_ends = []; if ( empty( $beginnings_and_ends[ $date ] ) ) { $beginnings_and_ends[ $date ] = [ 'beginning' => tribe_beginning_of_day( $date ), 'end' => tribe_end_of_day( $date ), ]; $beginnings_and_ends[ $date ]['beginning_timestamp'] = strtotime( $beginnings_and_ends[ $date ]['beginning'] ); $beginnings_and_ends[ $date ]['end_timestamp'] = strtotime( $beginnings_and_ends[ $date ]['end'] ); } return $beginnings_and_ends[ $date ][ $key ]; } /** * Breaks the possible collection of events down by grid date * * @param string $date Y-m-d formatted date to retrieve events for * * @return array */ private function get_event_ids_by_day( $date ) { if ( ! $this->event_ids_by_day ) { $this->event_ids_by_day = []; // Let's loop over all of the events in the month and assign them to days foreach ( $this->events_in_month as $event ) { // if we're querying by category and the event doesn't have it, skip the event if ( ! empty ( $this->queried_event_cats ) ) { if ( ! has_term( $this->queried_event_cats, Tribe__Events__Main::TAXONOMY, $event ) ) { continue; } } $event_start = strtotime( tribe_get_start_date( $event->ID, true, Tribe__Date_Utils::DBDATETIMEFORMAT ) ); $event_end = strtotime( tribe_get_end_date( $event->ID, true, Tribe__Date_Utils::DBDATETIMEFORMAT ) ); $order = get_post_field( 'menu_order', $event->ID ); // Builds the Index to allow a better ordering of events $order_index = $order . ':' . $event_start . ':' . $event->ID; $start = date( 'Y-m-d', $event_start ); $end = date( 'Y-m-d', $event_end ); $beginning_of_start = $this->get_cutoff_details( $start, 'beginning' ); $beginning_of_start_timestamp = $this->get_cutoff_details( $start, 'beginning_timestamp' ); $end_of_start = $this->get_cutoff_details( $start, 'end' ); $end_of_start_timestamp = $this->get_cutoff_details( $start, 'end_timestamp' ); $beginning_of_end = $this->get_cutoff_details( $end, 'beginning' ); $beginning_of_end_timestamp = $this->get_cutoff_details( $end, 'beginning_timestamp' ); // if the start of the event is earlier than the beginning of the day, consider the event // as starting on the day before // // Example 1: // Assuming a cut-off of 6:00am and an event start date/time of August 2nd @ 5:00am. The // "start" DATE would be August 2nd and the beginning of the "start" DATE would be August // 2nd @ 6:00am. Therefore, the event start DATE shoud be altered to be a day earlier // (August 1st) (Note: the following if statement conditional would be true) if ( $event_start < $beginning_of_start_timestamp ) { $start = date( 'Y-m-d', strtotime( '-1 day', strtotime( $start ) ) ); } // Subtract a day from the $end if it is: // * earlier than the beginning of the start DATE OR // * earlier than the beginning of the end DATE OR // * earlier than the end of the start DATE (as long as the beginning of the end DATE is greater than that of the start DATE) // // Example 1: // Assuming a cut-off of 6:00am and an event end date/time of August 2nd @ 7:00am. The // "end" DATE would be August 2nd and the beginning of the "end" DATE would be August // 2nd @ 6:00am. Therefore, the event end DATE shoud remain as August 2nd. (Note: the // following if statement conditional would be false) // // Example 2: // Assuming a cut-off of 6:00am and an event end date/time of August 2nd @ 5:00am. The // "end" DATE would be August 2nd and the beginning of the "end" DATE would be August // 2nd @ 6:00am. Therefore, the event end DATE shoud be altered to be a day earlier // (August 1st) (Note: this following if statement conditional would be true) if ( $event_end < $beginning_of_start_timestamp || $event_end < $beginning_of_end_timestamp || ( $event_end < $end_of_start_timestamp && $beginning_of_end_timestamp > $end_of_start_timestamp ) ) { $end = date( 'Y-m-d', strtotime( '-1 day', strtotime( $end ) ) ); } // determine if there's a difference in days between start and end $diff = strtotime( $end ) - strtotime( $start ); if ( $diff > 0 ) { // There IS a difference. How many days? $diff_in_days = $diff / DAY_IN_SECONDS; // add the event to each day until the event end $new_start = $start; for ( $i = 0; $i <= $diff_in_days; $i++ ) { if ( ! isset( $this->event_ids_by_day[ $new_start ] ) ) { $this->event_ids_by_day[ $new_start ] = []; } $this->event_ids_by_day[ $new_start ][ $order_index ] = $event->ID; $new_start = date( 'Y-m-d', strtotime( '+1 day', strtotime( $new_start ) ) ); } } else { // nope. The event is a single day event. Add it to the array if ( ! isset( $this->event_ids_by_day[ $start ] ) ) { $this->event_ids_by_day[ $start ] = []; } $this->event_ids_by_day[ $start ][ $order_index ] = $event->ID; } } // Now that we've built our event_ids_by_day, let's array_unique and sort foreach ( $this->event_ids_by_day as &$day ) { $day = array_unique( $day ); ksort( $day ); } } if ( empty( $this->event_ids_by_day[ $date ] ) ) { return []; } return $this->event_ids_by_day[ $date ]; } /** * Get the events for a single day * * @param string $date * * @return WP_Query */ private function get_daily_events( $date ) { /** * Filters the WP_Query object that will be returned for daily events on a date. * * If the value returned from this filter is not `null` then the method will bail * and return the filter return value. * * @since 4.6.24 * * @param WP_Query|null $daily_events The WP_Query object the template will loop on * to print the daily events; initially `null`. * @param string $date The day date in `Y-m-d` format. */ $daily_events = apply_filters( 'tribe_events_month_daily_events', null, $date ); if ( null !== $daily_events ) { return $daily_events; } $event_ids_on_date = $this->get_event_ids_by_day( $date ); // post__in doesn't work when it's empty, so just don't run the query if there are no IDs if ( empty( $event_ids_on_date ) ) { return new WP_Query(); } /** * Since we've already got the post IDs of the events fitting the search criteria * we can unset this to avoid furhter date-based filtering from happening. */ unset( $this->args['eventDate'] ); /* * This will skip updating term and meta caches - those were already * updated in `$this->set_events_in_month()`. * We run another query to make sure the ordering applies correctly. * Expected order of events: sticky events, ongoing multi day events, all day events, then by start time. */ $args = wp_parse_args( [ 'eventDisplay' => 'month', 'posts_per_page' => $this->events_per_day, 'post__in' => $event_ids_on_date, 'update_post_term_cache' => false, 'update_post_meta_cache' => false, 'no_found_rows' => false, 'do_not_inject_date' => true, // Don't replace `orderby` without taking in cosideration `menu_order`. 'orderby' => 'post__in', ], $this->args ); // If the request is false or not set we assume the request is for all events, not just featured ones. if ( tribe( 'tec.featured_events' )->featured_events_requested() || ( isset( $this->args['featured'] ) && tribe_is_truthy( $this->args['featured'] ) ) ) { $args['featured'] = true; } else { /** * Unset due to how queries featured argument is expected to be non-existent. * * @see #127272 */ if ( isset( $args['featured'] ) ) { unset( $args['featured'] ); } } /** * Filter Daily Events Query Arguments. * * @param array $args an array of daily events query. * */ $args = apply_filters( 'tribe_events_month_daily_events_query_args', $args ); return tribe_get_events( $args, true ); } /** * Sets up an array of $days based on the current query, that can be used in the calendar loop * */ public function setup_view() { if ( $this->use_cache && $this->html_cache->get() !== false ) { return; } $days = []; $date = $this->first_grid_date; // Start with the first grid date // Populate complete date range including leading/trailing days from adjacent months while ( $date <= $this->final_grid_date ) { $day_events = $this->get_daily_events( $date ); $day = (int) substr( $date, - 2 ); $prev_month = (int) substr( $date, 5, 2 ) < (int) substr( $this->requested_date, 5, 2 ); $next_month = (int) substr( $date, 5, 2 ) > (int) substr( $this->requested_date, 5, 2 ); $month_type = self::CURRENT_MONTH; if ( $prev_month ) { $month_type = self::PREVIOUS_MONTH; } if ( $next_month ) { $month_type = self::NEXT_MONTH; } $days[] = [ 'daynum' => $day, 'daynum-id' => Tribe__Events__Utils__Id_Generator::generate_id( $day, $day ), 'date' => $date, 'events' => $day_events, 'total_events' => $day_events->found_posts, 'view_more' => ( $day_events->found_posts > $this->events_per_day && $this->events_per_day >= 1 ) ? self::view_more_link( $date ) : false, 'month' => $month_type, ]; // Record the indicies marking the portion of the array relating to the current month if ( ! isset( $this->current_month_begins ) && self::CURRENT_MONTH === $month_type ) { $this->current_month_begins = count( $days ) - 1; } if ( isset( $this->current_month_begins ) && ! isset( $this->current_month_ends ) && self::CURRENT_MONTH !== $month_type ) { $this->current_month_ends = count( $days ) - 1; } // Advance forward one day $date = date( Tribe__Date_Utils::DBDATEFORMAT, strtotime( "$date +1 day" ) ); } // If the month ended without bleeding into the next month, our current_month_ends property may not be set if ( ! isset( $this->current_month_ends ) ) { $this->current_month_ends = count( $days ) - 1; } // store set of found days for use in calendar loop functions self::$calendar_days = $days; } /** * Returns the requested date as a Y-m (yyyy-mm) formatted string. * * If the requested date is invalid (such as 1984-25) the current month is returned instead and * an appropriate notice presented to the user. * * @return string */ protected function requested_date() { // We expect the date to be Y-m (yyyy-mm) format, ie year and date only $date = isset( $this->args['eventDate'] ) ? $this->args['eventDate'] : tribe_get_month_view_date(); // Test and return unmodified if valid if ( false !== strtotime( $date . '-01' ) ) { return $date; } else { Tribe__Notices::set_notice( 'requested-date-invalid', sprintf( esc_html__( 'The requested date "%s" was not valid – showing the current month instead', 'the-events-calendar' ), esc_html( $date ) ) ); return date_i18n( 'Y-m' ); } } /** * Loop through the $_REQUEST and find all tribe bar args. * * @return array */ protected static function get_tribe_bar_args() { $tribe_bar_args = []; foreach ( $_REQUEST as $key => $value ) { if ( $value && strpos( $key, 'tribe' ) === 0 && $key != 'tribe-bar-date' ) { $tribe_bar_args[ $key ] = $value; } } return $tribe_bar_args; } /** * Return the date of the first day in the month view grid. * * This is not necessarily the 1st of the specified month, rather it is the date of the * first grid cell which could be anything upto 6 days earlier than the 1st of the month. * * @param string $month * @param integer $start_of_week * * @return bool|string (Y-m-d) */ public static function calculate_first_cell_date( $month, $start_of_week = null ) { if ( null === $start_of_week ) { $start_of_week = (int) get_option( 'start_of_week', 0 ); } $day_1 = Tribe__Date_Utils::first_day_in_month( $month ); if ( $day_1 < $start_of_week ) { $day_1 += 7; } $diff = $day_1 - $start_of_week; if ( $diff >= 0 ) { $diff = "-$diff"; } try { $date = new DateTime( $month ); $date = new DateTime( $date->format( 'Y-m-01' ) ); $date->modify( "$diff days" ); return $date->format( Tribe__Date_Utils::DBDATEFORMAT ); } catch ( Exception $e ) { return false; } } /** * Return the date of the first day in the month view grid. * * This is not necessarily the last day of the specified month, rather it is the date of * the final grid cell which could be anything upto 6 days into the next month. * * @param string $month * @param integer $start_of_week * * @return bool|string (Y-m-d) */ public static function calculate_final_cell_date( $month, $start_of_week = null ) { if ( null === $start_of_week ) { $start_of_week = (int) get_option( 'start_of_week', 0 ); } $last_day = Tribe__Date_Utils::last_day_in_month( $month ); $end_of_week = Tribe__Date_Utils::week_ends_on( $start_of_week ); if ( $end_of_week < $last_day ) { $end_of_week += 7; } $diff = $end_of_week - $last_day; if ( $diff >= 0 ) { $diff = "+$diff"; } try { $date = new DateTime( $month ); $date = new DateTime( $date->format( 'Y-m-t' ) ); $date->modify( "$diff days" ); return $date->format( Tribe__Date_Utils::DBDATEFORMAT ); } catch ( Exception $e ) { return false; } } /** * Checks whether there are more calendar days to display * * @return bool True if calendar days are available, false if not. */ public static function have_days() { if ( self::$current_day + 1 < count( self::$calendar_days ) ) { return true; } elseif ( self::$current_day + 1 == count( self::$calendar_days ) && count( self::$calendar_days ) > 0 ) { do_action( 'tribe_events_calendar_loop_end' ); // Do some cleaning up after the loop self::rewind_days(); } return false; } /** * Advances the internal day counter (and week counter, if appropriate) * */ public static function the_day() { if ( self::have_days() ) { self::$current_day ++; if ( self::$current_day % 7 == 0 ) { self::$current_week ++; } } } /** * Rewind the posts and reset post index. * */ public static function rewind_days() { self::$current_day = - 1; self::$current_week = - 1; } /** * Returns the current day according to self::$current_day * * @return array|boolean */ public static function get_current_day() { if ( count( self::$calendar_days ) && self::$current_day < count( self::$calendar_days ) && isset( self::$calendar_days[ self::$current_day ] ) ) { return self::$calendar_days[ self::$current_day ]; } return false; } /** * Generates and returns a set of classes for the current day. * * @return string */ public static function day_classes() { $current_day = self::get_current_day(); $calendar_day = Tribe__Date_Utils::date_only( $current_day['date'] ); $today = date_i18n( Tribe__Date_Utils::DBDATEFORMAT ); // Start by determining which month we're looking at if ( $current_day['month'] == self::CURRENT_MONTH ) { $classes = 'tribe-events-thismonth'; } else { $classes = 'tribe-events-othermonth'; } // Check if the calendar day is in the past, present, or future if ( $calendar_day < $today ) { $classes .= ' tribe-events-past'; } elseif ( $calendar_day === $today ) { $classes .= ' tribe-events-present'; } elseif ( $calendar_day > $today ) { $classes .= ' tribe-events-future'; } // The day has some events if ( $current_day['total_events'] > 0 ) { $classes .= ' tribe-events-has-events'; } // Needed for mobile js $daynum = date( 'd', strtotime( $calendar_day ) ); $classes .= ' mobile-trigger tribe-event-day-' . $daynum; // Determine which column of the grid the day is in $column = ( self::$current_day ) - ( self::$current_week * 7 ); if ( $column > 0 && ( $column % 4 == 0 || $column % 5 == 0 || $column % 6 == 0 ) ) { $classes .= ' tribe-events-right'; } return $classes; } /** * Returns self::$current_week * * @return int $current_week */ public static function get_current_week() { return self::$current_week; } /** * Generates and returns a set of classes for the current day * * @param string $classes = '' * * @return string Classes */ public function event_classes( $classes = '' ) { $day = self::get_current_day(); if ( ! isset( $day['events'] ) ) { return $classes; } $post = $day['events']->post; // @todo [BTRIA-593]: Review whether the erasure of any existing classes is generally desirable. $classes = []; $tribe_cat_slugs = tribe_get_event_cat_slugs( $post->ID ); foreach ( $tribe_cat_slugs as $tribe_cat_slug ) { $classes[] = 'tribe-events-category-' . $tribe_cat_slug; } $classes = array_merge( $classes, get_post_class( '', $post->ID ) ); if ( $venue_id = tribe_get_venue_id( $post->ID ) ) { $classes[] = 'tribe-events-venue-' . $venue_id; } foreach ( tribe_get_organizer_ids( $post->ID ) as $organizer_id ) { $classes[] = 'tribe-events-organizer-' . $organizer_id; } if ( $day['events']->current_post + 1 == $day['events']->post_count ) { $classes[] = 'tribe-events-last'; } // Mark 'featured' events if ( tribe( 'tec.featured_events' )->is_featured( $post->ID ) ) { $classes[] = 'tribe-event-featured'; } return $classes; } /** * Month View Ajax Handler * */ public function ajax_response() { if ( isset( $_POST['eventDate'] ) && $_POST['eventDate'] ) { Tribe__Events__Query::init(); Tribe__Events__Main::instance()->displaying = 'month'; global $wp_query; $wp_query = tribe_get_events( $this->args, true ); ob_start(); tribe_get_view( 'month/content' ); $response = [ 'html' => ob_get_clean(), 'success' => true, 'view' => 'month', ]; apply_filters( 'tribe_events_ajax_response', $response ); header( 'Content-type: application/json' ); echo json_encode( $response ); die(); } } public function has_events() { return (bool) $this->events_in_month; } /** * Check if the month has events when all the filters have been applied. * * @since 4.6.19 * * @return bool */ public function has_events_filtered() { if ( 'month' !== Tribe__Events__Main::instance()->displaying ) { return false; } if ( ! $wp_query = tribe_get_global_query_object() ) { return false; } // Get the date from the main query $event_date = $wp_query->get( 'eventDate' ); // If we don't have the date, get the current date $month = empty( $event_date ) ? tribe_get_month_view_date() : $wp_query->get( 'eventDate' ); // prepare the args for this month $args = [ 'eventDisplay' => 'custom', 'start_date' => self::calculate_first_cell_date( $month ), 'end_date' => self::calculate_final_cell_date( $month ), 'posts_per_page' => -1, 'hide_upcoming' => true, ]; // check if we should take care of taxonomy if ( $wp_query->get( Tribe__Events__Main::TAXONOMY, false ) !== false ) { $args[ Tribe__Events__Main::TAXONOMY ] = $wp_query->get( Tribe__Events__Main::TAXONOMY ); } // See if we have events for $events = tribe_get_events( $args ); return (bool) $events; } } // class Tribe__Events__Template__Month }