HEX
Server: Apache/2
System: Linux server-80-13-140-150.da.direct 5.14.0-362.24.1.el9_3.0.1.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Apr 4 22:31:43 UTC 2024 x86_64
User: cpt (1004)
PHP: 8.1.24
Disabled: exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: /home/cpt/public_html/wp-content/plugins/wp-fullcalendar/wp-fullcalendar.php
<?php
/*
Plugin Name: WP FullCalendar
Version: 1.6
Text Domain: wp-fullcalendar
Plugin URI: https://wordpress.org/extend/plugins/wp-fullcalendar/
Description: Uses the jQuery FullCalendar plugin to create a stunning calendar view of events, posts and eventually other CPTs. Integrates well with Events Manager
Author: Pixelite
Author URI: https://pixelite.com
*/

/*
Copyright (c) 2025, Marcus Sykes

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
*/

define('WPFC_VERSION', '1.6');
define('WPFC_UI_VERSION', '1.12'); //jQuery 1.11.x

class WP_FullCalendar {
	static $args = array();

	public static function init() {
		//Scripts
		if ( !is_admin() ) { //show only in public area
			add_action('wp_enqueue_scripts', array('WP_FullCalendar','enqueue_scripts'));
			//shortcodes
			add_shortcode('fullcalendar', array('WP_FullCalendar','calendar'));
			add_shortcode('events_fullcalendar', array('WP_FullCalendar','calendar')); //depreciated, will be gone by 1.0
		} else {
			//admin actions
			include('wpfc-admin.php');
		}
		add_action('wp_ajax_WP_FullCalendar', array('WP_FullCalendar','ajax') );
		add_action('wp_ajax_nopriv_WP_FullCalendar', array('WP_FullCalendar','ajax') );
		add_action('wp_ajax_wpfc_qtip_content', array('WP_FullCalendar','qtip_content') );
		add_action('wp_ajax_nopriv_wpfc_qtip_content', array('WP_FullCalendar','qtip_content') );
		//base arguments
		self::$args['type'] = get_option('wpfc_default_type', 'event');
		//START Events Manager Integration - will soon be removed
		if ( defined('EM_VERSION') && EM_VERSION <= 5.62 ) {
			if ( !empty($_REQUEST['action']) && $_REQUEST['action'] = 'WP_FullCalendar' && !empty($_REQUEST['type']) && $_REQUEST['type'] == EM_POST_TYPE_EVENT ) {
				//reset the start/end times for Events Manager 5.6.1 and less, to avoid upgrade-breakages
				$_REQUEST['start'] = $_POST['start'] = strtotime($_REQUEST['start']); //maybe excessive, but easy sanitization
				$_REQUEST['end'] = $_POST['end'] = strtotime($_REQUEST['end']);
			}
		}
		if ( defined('EM_VERSION') && is_admin() ) {
			include('wpfc-events-manager.php');
		}
		//END Events Manager Integration
	}
	
	public static function enqueue_scripts() {
		global $wp_query;
		$min = defined('WP_DEBUG') && WP_DEBUG ? '':'.min';
		$obj_id = is_home() ? '-1':$wp_query->get_queried_object_id();
		$wpfc_scripts_limit = get_option('wpfc_scripts_limit');
		if ( empty($wpfc_scripts_limit) || in_array($obj_id, explode(',', $wpfc_scripts_limit)) ) {
			//Scripts
			$jquery_dependencies = array('jquery', 'jquery-ui-core','jquery-ui-widget','jquery-ui-position', 'jquery-ui-selectmenu', 'jquery-ui-tooltip' ,'moment');
			if ( ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) || ( defined('WPFC_DEBUG') && WPFC_DEBUG ) ) {
				wp_enqueue_script('wp-fullcalendar', plugins_url('includes/js/fullcalendar.js', __FILE__), $jquery_dependencies, WPFC_VERSION); //jQuery will load as dependency
				wp_enqueue_script('popper.js', plugins_url('includes/js/popper.js', __FILE__), array('wp-fullcalendar'), WPFC_VERSION); //jQuery will load as dependency
				wp_enqueue_script('tippy.js', plugins_url('includes/js/tippy.js', __FILE__), array('wp-fullcalendar','popper.js'), WPFC_VERSION); //jQuery will load as dependency
			} else {
				wp_enqueue_script('wp-fullcalendar', plugins_url('includes/js/main.js', __FILE__), $jquery_dependencies, WPFC_VERSION); //jQuery will load as dependency
			}
			self::localize_script();
			//Styles
			wp_enqueue_style('wp-fullcalendar', plugins_url('includes/css/main.css', __FILE__), array(), WPFC_VERSION);
			//get tooltip style
			if ( get_option('wpfc_qtips') ) {
				$style = get_option('wpfc_tippy_style', 'light-border');
				//you can add a tippy custom style to your theme/plugins/wp-fullcalendar folder
				if ( file_exists(get_stylesheet_directory() . '/plugins/wp-fullcalendar/tippy/' . $style . '.css') ) {
					$wpfc_tippy_css = get_stylesheet_directory_uri() . '/plugins/wp-fullcalendar/tippy/' . $style . '.css';
				} else {
					$wpfc_tippy_css = plugins_url('includes/css/tippy/' . $style . '.css', __FILE__);
				}
				wp_enqueue_style('wp-fullcalendar-tippy-' . $style, $wpfc_tippy_css, array(), WPFC_VERSION);
			}
			//Load custom style or jQuery UI Theme
			$wpfc_theme = get_option('wpfc_theme_css');
			if ( preg_match('/\.css$/', $wpfc_theme) ) {
				//user-defined style within the themes/themename/plugins/wp-fullcalendar/ folder
				//if you're using jQuery UI Theme-Roller, you need to include the jquery-ui-css framework file too, you could do this using the @import CSS rule or include it all in your CSS file
				if ( file_exists(get_stylesheet_directory() . '/plugins/wp-fullcalendar/' . $wpfc_theme) ) {
					$wpfc_theme_css = get_stylesheet_directory_uri() . '/plugins/wp-fullcalendar/' . $wpfc_theme;
					wp_deregister_style('jquery-ui'); 
					wp_enqueue_style('jquery-ui', $wpfc_theme_css, array('wp-fullcalendar'), WPFC_VERSION);
				}
			} elseif ( !empty($wpfc_theme) ) {
				//We'll find the current jQuery UI version and attempt to load the right version of jQuery UI, otherwise we'll load the default. This allows backwards compatability from 3.6 onwards.
				global $wp_scripts;
				$jquery_ui_version = preg_replace('/\.[0-9]+$/', '', $wp_scripts->registered['jquery-ui-core']->ver);
				if ( !empty($jquery_ui_version) && $jquery_ui_version != WPFC_UI_VERSION ) {
					$jquery_ui_css_versions = glob( $plugin_path = plugin_dir_path(__FILE__) . '/includes/css/jquery-ui-' . $jquery_ui_version . '*', GLOB_ONLYDIR);
					if ( !empty($jquery_ui_css_versions) ) {
						//use backwards compatible theme
						$jquery_ui_css_folder = str_replace(plugin_dir_path(__FILE__), '', array_pop($jquery_ui_css_versions));
						$jquery_ui_css_uri = plugins_url(trailingslashit($jquery_ui_css_folder) . $wpfc_theme . "/jquery-ui$min.css", __FILE__);
						$wpfc_theme_css = plugins_url(trailingslashit($jquery_ui_css_folder) . $wpfc_theme . '/theme.css', __FILE__);
					}
				}
				if ( empty($wpfc_theme_css) ) {
					//use default theme
					$jquery_ui_css_uri = plugins_url('/includes/css/jquery-ui/' . $wpfc_theme . "/jquery-ui$min.css", __FILE__);
					$wpfc_theme_css = plugins_url('/includes/css/jquery-ui/' . $wpfc_theme . '/theme.css', __FILE__);
				}
				if ( !empty($wpfc_theme_css) ) {   
					wp_deregister_style('jquery-ui'); 
					wp_enqueue_style('jquery-ui', $jquery_ui_css_uri, array('wp-fullcalendar'), WPFC_VERSION);
					wp_enqueue_style('jquery-ui-theme', $wpfc_theme_css, array('wp-fullcalendar'), WPFC_VERSION);
				}
			}
		}
	}

	public static function localize_script() {
		$js_vars = array();
		$schema = is_ssl() ? 'https':'http';
		$js_vars['ajaxurl'] = add_query_arg('action', 'WP_FullCalendar', admin_url('admin-ajax.php', $schema));
		$js_vars['firstDay'] =  get_option('start_of_week');
		$js_vars['wpfc_theme'] = get_option('wpfc_theme_css') ? 'jquery-ui':false;
		$js_vars['wpfc_limit'] = get_option('wpfc_limit', 3);
		$js_vars['wpfc_limit_txt'] = get_option('wpfc_limit_txt', 'more ...');
		//FC options
		$js_vars['timeFormat'] = get_option('wpfc_timeFormat', 'h(:mm)t');
		$js_vars['defaultView'] = get_option('wpfc_defaultView', 'month');
		$js_vars['weekends'] = get_option('wpfc_weekends', true) ? 'true':'false';
		$js_vars['header'] = new stdClass();
		$js_vars['header']->left = 'prev,next today';
		$js_vars['header']->center = 'title';
		$js_vars['header']->right = implode(',', get_option('wpfc_available_views', array('month','basicWeek','basicDay')));
		$js_vars['header'] = apply_filters('wpfc_calendar_header_vars', $js_vars['header']); 
		//qtip options
		$js_vars['wpfc_qtips'] = get_option('wpfc_qtips', true) == true;
		if ( $js_vars['wpfc_qtips'] ) {
			$js_vars['tippy_theme'] = get_option('wpfc_tippy_theme', 'light-border');
			$js_vars['tippy_placement'] = get_option('wpfc_tippy_placement', 'auto');
			$js_vars['tippy_loading'] = get_option('wpfc_tippy_placeholder', 'Loading...');
		}
		//calendar translations
		wp_localize_script('wp-fullcalendar', 'WPFC', apply_filters('wpfc_js_vars', $js_vars));
	}

	/**
	 * Catches ajax requests by fullcalendar
	 */
	public static function ajax() {
		global $post;
		//sort out args
		unset($_REQUEST['month']); //no need for these two
		unset($_REQUEST['year']);
		//maybe excessive, but easy sanitization of start/end query params
		$_REQUEST['start'] = $_POST['start'] = date('Y-m-d', strtotime($_REQUEST['start']));
		$_REQUEST['end'] = $_POST['end'] = date('Y-m-d', strtotime($_REQUEST['end']));
		$args = array ('scope'=>array($_REQUEST['start'], $_REQUEST['end']), 'owner'=>false, 'status'=>1, 'order'=>'ASC', 'orderby'=>'post_date','full'=>1);
		//get post type and taxonomies, determine if we're filtering by taxonomy
		$post_types = get_post_types(array('public'=>true), 'names');
		$post_type = !empty($_REQUEST['type']) && in_array($_REQUEST['type'], $post_types) ? $_REQUEST['type']:get_option('wpfc_default_type');
		$args['post_type'] = $post_type;
		$args['post_status'] = 'publish'; //only show published status
		$args['posts_per_page'] = -1;
		if ( $args['post_type'] == 'attachment' ) {
			$args['post_status'] = 'inherit';
		}
		$args['tax_query'] = array();
		foreach ( get_object_taxonomies($post_type) as $taxonomy_name ) {
			if ( !empty($_REQUEST[$taxonomy_name]) ) {
				$args['tax_query'][] = array(
					'taxonomy' => $taxonomy_name,
					'field' => 'id',
					'terms' => absint($_REQUEST[$taxonomy_name]),
				);
			}
		}
		//initiate vars
		$args = apply_filters('wpfc_fullcalendar_args', $args);
		$limit = get_option('wpfc_limit', 3);
		$items = array();
		$item_dates_more = array();
		$item_date_counts = array();
		
		//Create our own loop here and tamper with the where sql for date ranges, as per http://codex.wordpress.org/Class_Reference/WP_Query#Time_Parameters
		function wpfc_temp_filter_where( $where = '' ) {
			global $wpdb;
			$where .= $wpdb->prepare(' AND post_date >= %s AND post_date < %s', $_REQUEST['start'], $_REQUEST['end']);
			return $where;
		}
		add_filter( 'posts_where', 'wpfc_temp_filter_where' );
		do_action('wpfc_before_wp_query');
		$the_query = new WP_Query( $args );
		remove_filter( 'posts_where', 'wpfc_temp_filter_where' );
		//loop through each post and slot them into the array of posts to return to browser
		while ( $the_query->have_posts() ) {
			$the_query->the_post();
			$color = '#a8d144';
			$post_date = substr($post->post_date, 0, 10);
			$post_timestamp = strtotime($post->post_date);
			if ( empty($item_date_counts[$post_date]) || $item_date_counts[$post_date] < $limit ) {
				$title = $post->post_title;
				$item = array ('title' => $title, 'color' => $color, 'start' => date('Y-m-d\TH:i:s', $post_timestamp), 'end' => date('Y-m-d\TH:i:s', $post_timestamp), 'url' => get_permalink($post->ID), 'post_id' => $post->ID, 'nonce' => wp_create_nonce('wpfc_item_nonce_' . $post->ID) );
				$items[] = apply_filters('wpfc_ajax_post', $item, $post);
				$item_date_counts[$post_date] = ( !empty($item_date_counts[$post_date]) ) ? $item_date_counts[$post_date]+1:1;
			} elseif ( empty($item_dates_more[$post_date]) ) {
				$item_dates_more[$post_date] = 1;
				$day_ending = $post_date . 'T23:59:59';
				//TODO archives not necesarrily working
				$more_array = array ('title' => get_option('wpfc_limit_txt', 'more ...'), 'color' => get_option('wpfc_limit_color', '#fbbe30'), 'start' => $day_ending, 'post_id' => 0, 'className' => 'wpfc-more');
				global $wp_rewrite;
				$archive_url = get_post_type_archive_link($post_type);
				if ( !empty($archive_url) || $post_type == 'post' ) { //posts do have archives
					$archive_url = trailingslashit($archive_url);
					$archive_url .= $wp_rewrite->using_permalinks() ? date('Y/m/', $post_timestamp):'?m=' . date('Ym', $post_timestamp);
					$more_array['url'] = $archive_url;
				}
				$items[] = apply_filters('wpfc_ajax_more', $more_array, $post_date);
			}
		}
		echo json_encode(apply_filters('wpfc_ajax', $items));
		die(); //normally we'd wp_reset_postdata();
	}

	/**
	 * Called during AJAX request for qtip content for a calendar item 
	 */
	public static function qtip_content() {
		$content = '';
		if ( !empty($_REQUEST['post_id']) && !empty($_REQUEST['nonce']) && wp_verify_nonce($_REQUEST['nonce'], 'wpfc_item_nonce_' . $_REQUEST['post_id']) ) {
			$post = get_post($_REQUEST['post_id']);
			if ( $post->post_type == 'attachment' ) {
				$content = wp_get_attachment_image($post->ID, 'thumbnail');
			} else {
				$content = ( !empty($post) ) ? $post->post_content : '';
				if ( get_option('wpfc_qtips_image', 1) ) {
					$post_image = get_the_post_thumbnail($post->ID, array(get_option('wpfc_qtip_image_w', 75),get_option('wpfc_qtip_image_h', 75)));
					if ( !empty($post_image) ) {
						$content = '<div style="float:left; margin:5px 10px 5px 0px;">' . $post_image . '</div>' . $content;
					}
				}
			}
		}
		echo apply_filters('wpfc_qtip_content', $content);
		die();
	}
	
	/**
	 * Returns the calendar HTML setup and primes the js to load at wp_footer
	 *
	 * @param array $args
	 * @return string
	 */
	public static function calendar( $args = array() ) {
		if (is_array($args) ) {
			self::$args = array_merge(self::$args, $args);
		}
		self::$args['month'] = ( !empty($args['month']) ) ? absint($args['month']-1):date('m', current_time('timestamp'))-1;
		self::$args['year'] = ( !empty($args['year']) ) ? absint($args['year']):date('Y', current_time('timestamp'));
		self::$args = apply_filters('wpfc_fullcalendar_args', self::$args);
		add_action('wp_footer', array('WP_FullCalendar','footer_js'));
		ob_start();
		?>
		<div class="wpfc-calendar-wrapper"><form class="wpfc-calendar" id="wpfc-calendar-<?php echo esc_attr(rand(0, 99999)); ?>"></form><div class="wpfc-loading"></div></div>
		<div class="wpfc-calendar-search" style="display:none;">
			<?php
				$post_type = !empty(self::$args['type']) ? self::$args['type']:'post';
				//figure out what taxonomies to show
				$wpfc_post_taxonomies = get_option('wpfc_post_taxonomies');
				$search_taxonomies = !empty($wpfc_post_taxonomies[$post_type]) ? array_keys($wpfc_post_taxonomies[$post_type]):array();
			if ( !empty($args['taxonomies']) ) {
				//we accept taxonomies in arguments
				$search_taxonomies = explode(',', $args['taxonomies']);
				array_walk($search_taxonomies, 'trim');
				unset(self::$args['taxonomies']);
			}
				//go through each post type taxonomy and display if told to
			foreach ( get_object_taxonomies($post_type) as $taxonomy_name ) {
				$taxonomy = get_taxonomy($taxonomy_name);
				if ( count(get_terms($taxonomy_name, array('hide_empty'=>1))) > 0 && in_array($taxonomy_name, $search_taxonomies) ) {
					$default_value = !empty(self::$args[$taxonomy_name]) ? self::$args[$taxonomy_name]:0;
					$taxonomy_args = array( 'echo'=>true, 'hide_empty' => 1, 'name' => $taxonomy_name, 'hierarchical' => true, 'class' => 'wpfc-taxonomy ' . $taxonomy_name, 'taxonomy' => $taxonomy_name, 'selected'=> $default_value, 'show_option_all' => $taxonomy->labels->all_items);
					wp_dropdown_categories( apply_filters('wpmfc_calendar_taxonomy_args', $taxonomy_args, $taxonomy ) );
				}
			}
				do_action('wpfc_calendar_search', self::$args);
			?>
		</div>
		<script type="text/javascript">
			WPFC.data = {
				action : 'WP_FullCalendar',
				<?php
					//these arguments were assigned earlier on when displaying the calendar, and remain constant between ajax calls
					$strings = array();
					foreach ( self::$args as $key => $arg ) {
						echo "'" . esc_js($key) . "' : ";
						echo is_numeric($arg) ? (int) $arg : "'" . esc_js($arg) . "'";
						echo ',';
					}
				?>
			 };
			WPFC.month = <?php echo esc_js(self::$args['month']); ?>;
			WPFC.year = <?php echo esc_js(self::$args['year']); ?>;
		</script>
		<?php
		do_action('wpfc_calendar_displayed', $args);
		return ob_get_clean();
	}

	/**
	 * Run at wp_footer if a calendar is output earlier on in the page.
	 *
	 * @uses self::$args - which was modified during self::calendar()
	 */
	public static function footer_js() {
		?>
		<script type='text/javascript'>
		<?php 
		  include('includes/js/inline.js');
		  $locale_code = strtolower(str_replace('_', '-', get_locale()));
		  $file_long = dirname(__FILE__) . '/includes/js/locale/' . $locale_code . '.js';
		  $file_short = dirname(__FILE__) . '/includes/js/locale/' . substr ( $locale_code, 0, 2 ) . '.js';
		if ( file_exists($file_short) ) {
			include_once($file_short);
		} elseif ( file_exists($file_long) ) {
			include_once($file_long);
		}
		?>
		</script>
		<?php
	}
}
add_action('plugins_loaded', array('WP_FullCalendar','init'), 100);

// action links
add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'wpfc_settings_link', 10, 1);
function wpfc_settings_link( $links) {
	$new_links = array(); //put settings first
	$new_links[] = '<a href="' . admin_url('options-general.php?page=wp-fullcalendar') . '">' . __('Settings', 'wp-fullcalendar') . '</a>';
	return array_merge($new_links, $links);
}

// Add this plugin to EM's dev updates check (EM 5.9.9.2 and later)
add_filter('em_org_dev_versions', function( $plugin_slugs ) {
	$plugin_slugs['wp-fullcalendar'] = array(
		'slug' => plugin_basename( __FILE__ ),
		'version' => WPFC_VERSION,
	);
	return $plugin_slugs;
});