Source: my-calendar-pro.php

<?php
/**
 * My Calendar Pro, Premium Accessible Events Manager for WordPress
 *
 * @package     MyCalendarPro
 * @author      Joe Dolson
 * @copyright   2012-2025 Joe Dolson
 * @license     GPL-2.0+
 *
 * @wordpress-plugin
 * Plugin Name: My Calendar Pro
 * Plugin URI:  https://www.joedolson.com/my-calendar-pro/
 * Description: Expands the capabilities of My Calendar to add premium features.
 * Author:      Joe Dolson
 * Author URI:  https://www.joedolson.com
 * Text Domain: my-calendar-pro
 * License:     GPL-2.0+
 * License URI: http://www.gnu.org/license/gpl-2.0.txt
 * Domain Path: /lang
 * Version:     3.2.1
 * Requires Plugins: my-calendar
 */

/*
	Copyright 2012-2025  Joe Dolson (email : joe@joedolson.com)

	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.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

global $mcs_version, $wpdb;
$mcs_version = '3.2.1';

// The URL of the site with EDD installed.
define( 'EDD_MCP_STORE_URL', 'https://www.joedolson.com' );

if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
	// load our custom updater if it doesn't already exist.
	require __DIR__ . '/updates/EDD_SL_Plugin_Updater.php';
}

// retrieve our license key from the DB.
$license_key = ( ! defined( 'MCS_LICENSE_KEY' ) ) ? trim( get_option( 'mcs_license_key' ) ) : MCS_LICENSE_KEY;
// setup the updater.
$edd_updater = new EDD_SL_Plugin_Updater(
	EDD_MCP_STORE_URL,
	__FILE__,
	array(
		'version' => $mcs_version, // current version number.
		'license' => $license_key, // license key (used get_option above to retrieve from DB).
		'item_id' => 5734, // ID of this plugin.
		'author'  => 'Joe Dolson', // author of this plugin.
		'url'     => home_url(),
	)
);

// Define the tables used in My Calendar.
define( 'MY_CALENDAR_PAYMENTS_TABLE', $wpdb->prefix . 'my_calendar_payments' );

if ( function_exists( 'is_multisite' ) && is_multisite() ) {
	// Define the tables used in My Calendar.
	define( 'MY_CALENDAR_GLOBAL_PAYMENTS_TABLE', $wpdb->base_prefix . 'my_calendar_payments' );
}

/**
 * Checks for existence; used in My Calendar to check for support.
 */
function mcs_submissions() {
	return true;
}

add_action( 'init', 'mcs_load_textdomain' );
/**
 * Load internationalization.
 */
function mcs_load_textdomain() {
	// Shipped translations removed @v3.3.0.
	load_plugin_textdomain( 'my-calendar-pro', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );
}

require __DIR__ . '/inc/utilities.php';
require __DIR__ . '/my-calendar-payment-functions.php';
require __DIR__ . '/my-calendar-generator.php';
require __DIR__ . '/my-calendar-geolocation.php';
require __DIR__ . '/my-calendar-manage.php';
require __DIR__ . '/my-calendar-submit.php';
require __DIR__ . '/my-calendar-submit-ajax.php';
require __DIR__ . '/my-calendar-submit-payments.php';
require __DIR__ . '/my-calendar-notifications.php';
require __DIR__ . '/my-calendar-custom-fields.php';
require __DIR__ . '/my-calendar-default-fields.php';
require __DIR__ . '/classes/class-mc-submissions-widget.php';
require __DIR__ . '/my-calendar-submit-settings.php';
require __DIR__ . '/my-calendar-event-posts.php';
require __DIR__ . '/my-calendar-post-events.php';
require __DIR__ . '/my-calendar-advanced-search.php';
require __DIR__ . '/my-calendar-responsive-mode.php';
require __DIR__ . '/my-calendar-import.php';
require __DIR__ . '/my-calendar-api.php';
require __DIR__ . '/my-calendar-multilingual.php';
require __DIR__ . '/my-calendar-private-content.php';
require __DIR__ . '/my-calendar-hosts.php';
require __DIR__ . '/my-calendar-miscellaneous.php';
require __DIR__ . '/my-calendar-license.php';

if ( mcs_is_enabled( 'client-api' ) ) {
	require __DIR__ . '/my-calendar-api-client/post.php';
	require __DIR__ . '/my-calendar-api-client/settings.php';
	require __DIR__ . '/my-calendar-api-client/ui-admin.php';
}

if ( mcs_is_enabled( 'server-api' ) ) {
	require __DIR__ . '/my-calendar-api-server/api.php';
	require __DIR__ . '/my-calendar-api-server/settings.php';
	require __DIR__ . '/my-calendar-api-server/ui-public.php';
}

register_activation_hook( __FILE__, 'mcs_activation_hook' );
/**
 * Execute on activation. Check requirements.
 */
function mcs_activation_hook() {
	$required_php_version = '7.4.0';

	if ( version_compare( PHP_VERSION, $required_php_version, '<' ) ) {
		$plugin_data = get_plugin_data( __FILE__, false );
		// Translators: Plugin name, PHP version required, your PHP version.
		$message = sprintf( __( '%1$s requires PHP version %2$s or higher. Your current PHP version is %3$s', 'my-calendar-pro' ), $plugin_data['Name'], $required_php_version, phpversion() );
		wp_admin_notice(
			$message,
			array(
				'type' => 'error',
			)
		);
		deactivate_plugins( plugin_basename( __FILE__ ) );
		exit;
	}
	mcs_check();
}

add_action( 'admin_notices', 'mcs_license_notice' );
/**
 * Display license notice if needs current.
 *
 * @return string
 */
function mcs_license_notice() {
	global $current_screen;
	if ( stripos( $current_screen->id, 'my-calendar' ) ) {
		// only check license on main site in network environments.
		if ( is_main_site() ) {
			if ( 'true' === get_option( 'mcs_license_key_valid' ) || 'active' === get_option( 'mcs_license_key_valid' ) || 'valid' === get_option( 'mcs_license_key_valid' ) ) {
				return;
			}
			// Translators: License input URL.
			$message = sprintf( __( "You must <a href='%s'>enter your license key</a> to get support and updates for My Calendar Pro.", 'my-calendar-pro' ), admin_url( 'admin.php?page=my-calendar-submissions#mcs_license_tab' ) );

			if ( ! current_user_can( 'manage_options' ) ) {
				return;
			} else {
				wp_admin_notice(
					$message,
					array(
						'type' => 'error',
					)
				);
			}
		}
	}
}

add_action( 'init', 'mcs_register_actions', 9 );
/**
 * Register actions for My Calendar Pro.
 */
function mcs_register_actions() {
	add_action( 'wp_loaded', 'mcs_verify_receipt' );
	add_action( 'parse_request', 'mcs_receive_ipn' );
	add_action( 'parse_request', 'mcs_show_receipt' );
	add_action( 'mcs_complete_submission', 'mcs_notify_admin', 10, 4 );
	add_action( 'mcs_complete_submission', 'mcs_notify_submitter', 10, 4 );
	add_action( 'mc_transition_event', 'mcs_notify_submitter_transition', 10, 5 );
	add_filter( 'mc_generator_tabs', 'mcs_form_builder_tab', 10, 1 );
	add_filter( 'mc_generator_tab_content', 'mcs_form_builder_tab_content', 10, 2 );
}

add_action( 'widgets_init', 'mcs_register_widgets' );
/**
 * Register widgets for My CalendarPro.
 */
function mcs_register_widgets() {
	register_widget( 'My_Calendar_Advanced_Search' );
	register_widget( 'Mc_Submissions_Widget' );
}

/**
 * Check status of plug-in and install if necessary.
 */
function mcs_check() {
	global $wpdb, $mcs_version;
	$current_version = get_option( 'mcs_version' );
	// If current version matches, don't bother running this.
	if ( $current_version === $mcs_version ) {
		return true;
	}
	// Run the My Calendar DB updates first.
	if ( function_exists( 'mc_upgrade_db' ) ) {
		mc_upgrade_db();
	}
	// Lets see if this is first run and create a table if it is!
	// Assume this is not a new install until we prove otherwise.
	$new_install        = false;
	$my_calendar_exists = false;
	$upgrade_path       = array();

	$db_engine = defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ? 'sqlite' : 'mysql';
	if ( 'sqlite' !== $db_engine ) {
		$tables = $wpdb->get_results( 'show tables;' );
		foreach ( $tables as $table ) {
			foreach ( $table as $value ) {
				if ( MY_CALENDAR_PAYMENTS_TABLE === $value ) {
					$my_calendar_exists = true;
				}
			}
		}
	}
	if ( false === $my_calendar_exists ) {
		$new_install = true;
	}
	// having determined upgrade path, assign new version number.
	update_option( 'mcs_version', $mcs_version );
	// Now we've determined what the current install is or isn't.
	if ( true === $new_install ) {
		mcs_default_settings();
	} else {
		if ( version_compare( $current_version, '1.5.8', '<' ) ) {
			$upgrade_path[] = '1.5.8';
		}
		if ( version_compare( $current_version, '2.0.0', '<' ) ) {
			$upgrade_path[] = '2.0.0';
		}
		if ( version_compare( $current_version, '3.0.0', '<' ) ) {
			$upgrade_path[] = '3.0.0';
		}
	}
	// switch for different upgrade paths.
	foreach ( $upgrade_path as $upgrade ) {
		switch ( $upgrade ) {
			case '3.0.0':
				add_option( 'mcs_private_content', 'true' );
				mcs_update_database(); // Adds two new columns to payments table.
			case '2.0.0':
				delete_option( 'mcs_options' );
				delete_option( 'mcs_quantity' );
				break;
			case '1.5.8':
				delete_option( 'mcs-parsed-files' );
				delete_option( 'mcs-number-of-files' );
				delete_option( 'mcs-delimiter' );
				delete_option( 'mcs_parsing_now_0' );
				delete_option( 'mcs_parsing_now_1' );
				delete_option( 'mcs_parsing_now_2' );
				delete_option( 'mcs_parsing_now_3' );
				delete_option( 'mcs_parsing_now_4' );
				delete_option( 'mcs_parsing_now_5' );
				delete_option( 'mcs_parsing_now_6' );
				break;
		}
	}
}

/**
 * Generate submit page on installation.
 *
 * @param string $slug Proposed page slug.
 *
 * @return id postID
 */
function mcs_generate_submit_page( $slug ) {
	$current_user = wp_get_current_user();
	if ( ! get_page_by_path( $slug ) ) {
		$page      = array(
			'post_title'   => __( 'Submit Events', 'my-calendar-pro' ),
			'post_status'  => 'publish',
			'post_type'    => 'page',
			'post_author'  => $current_user->ID,
			'ping_status'  => 'closed',
			'post_content' => '<!-- wp:shortcode -->[submit_event]<!-- /wp:shortcode -->',
		);
		$post_ID   = wp_insert_post( $page );
		$post_slug = wp_unique_post_slug( $slug, $post_ID, 'publish', 'page', 0 );
		wp_update_post(
			array(
				'ID'        => $post_ID,
				'post_name' => $post_slug,
			)
		);
	} else {
		$post    = get_page_by_path( $slug );
		$post_ID = $post->ID;
	}
	update_option( 'mcs_submit_id', $post_ID );

	return $post_ID;
}

/**
 * Generate event edit page on installation.
 *
 * @param string $slug Proposed page slug.
 *
 * @return id postID
 */
function mcs_generate_edit_page( $slug ) {
	$current_user = wp_get_current_user();
	if ( ! get_page_by_path( $slug ) ) {
		$page      = array(
			'post_title'   => __( 'Edit Events', 'my-calendar-pro' ),
			'post_status'  => 'publish',
			'post_type'    => 'page',
			'post_author'  => $current_user->ID,
			'ping_status'  => 'closed',
			'post_content' => '[submitted_events]',
		);
		$post_ID   = wp_insert_post( $page );
		$post_slug = wp_unique_post_slug( $slug, $post_ID, 'publish', 'page', 0 );
		wp_update_post(
			array(
				'ID'        => $post_ID,
				'post_name' => $post_slug,
			)
		);
	} else {
		$post    = get_page_by_path( $slug );
		$post_ID = $post->ID;
	}
	update_option( 'mcs_edit_id', $post_ID );

	return $post_ID;
}

/**
 * Plugin default settings.
 *
 * @return void
 */
function mcs_default_settings() {
	global $mcs_version;

	update_option( 'mcs_criteria', '2' );
	update_option( 'mcs_ajax', 'true' );
	mcs_update_database();
	mcs_generate_submit_page( 'submit-events' );
	mcs_generate_edit_page( 'edit-events' );
	mcs_generate_search_page( 'advanced-event-search' );
	add_option( 'mcs_db_version', $mcs_version ); // sync db version to version.
}

/**
 * Return default settings.
 */
function mcs_get_default_settings() {
	$options = array(
		'fields'          => mcs_default_fields(),
		'location_fields' => mcs_default_location_fields(),
		'defaults'        => array(
			'mcs_response'                     => '
A new event has been submitted by {name}.

Title: {title}
Date & Time: {date}, {time}

Review this event: {edit_link}',
			'mcs_confirmation'                 => '
Thanks for proposing a new event, {name}!

Title: {title}
Date & Time: {date}, {time}

This event must be approved by a site administrator.',
			'mcs_edit_response'                => '
An event has been edited by {name}.

Title: {title}
Date & Time: {date}, {time}

Review this event: {edit_link}',
			'mcs_edit_confirmation'            => '
Thanks for editing your event, {name}!

Title: {title}
Date & Time: {date}, {time}',
			'mcs_subject'                      => 'New event on {blogname}',
			'mcs_edit_subject'                 => 'Event on {blogname} has been edited',
			'mcs_confirmation_subject'         => 'Your event submission has been received.',
			'mcs_edit_confirmation_subject'    => 'Your event submission has been edited.',
			'mcs_publication_subject'          => 'Your event at {blogname} has been published.',
			'mcs_publication'                  => 'Your submitted event {title} has been published.',
			'mcs_payment_response'             => '
A payment to create events has been submitted by {first_name} {last_name}.

New payment key: {key}
Paid: ${price} for {quantity} event/s',
			'mcs_payment_confirmation'         => '
Thanks for purchasing an event submission key for {blogname} a new event, {first_name}!

Your payment key: {key}. You paid ${price} for {quantity} event/s.
Your Receipt: {receipt}

You may use this key to submit your events.',
			'mcs_payment_subject'              => 'New event submission payment on {blogname}',
			'mcs_payment_confirmation_subject' => 'Your event submission payment has been received.',
			'mcs_payment_message'              => 'Payment is required to submit an event! Submission costs <strong>{price} {currency}</strong>.',
			'mcs_criteria'                     => 2,
			'mcs_payments'                     => 'false',
			'mcs_use_sandbox'                  => 'false',
			'mcs_submission_fee'               => '5.00',
			'mcs_currency'                     => 'USD',
			'mcs_check_conflicts'              => 'false',
			'mcs_upload_images'                => 'false',
		),
		'widget_defaults' => array(
			'title'      => 'Submit an Event',
			'categories' => 'true',
			'category'   => 1,
			'locations'  => 'choose',
			'location'   => '',
		),
	);

	return $options;
}

/**
 * These two functions are called from My Calendar via admin_head action
 */
function my_calendar_sub_js() {
	global $mcs_version;
	$admin_js = plugins_url( 'js/mcs-admin.min.js', __FILE__ );
	if ( SCRIPT_DEBUG ) {
		$mcs_version .= '-' . wp_rand( 10000, 100000 );
		$admin_js     = plugins_url( 'js/mcs-admin.js', __FILE__ );
	}
	if ( isset( $_GET['page'] ) && 'my-calendar-submissions' === $_GET['page'] ) {
		wp_enqueue_script( 'mc.tabs' );
	}
	if ( isset( $_GET['page'] ) && ( 'my-calendar-shortcodes' === $_GET['page'] || 'my-calendar-submissions' === $_GET['page'] ) ) {
		wp_enqueue_script( 'mcs.admin', $admin_js, array( 'jquery', 'wp-a11y' ), $mcs_version );
		wp_localize_script(
			'mcs.admin',
			'mcs_fields',
			array(
				'ajaxurl'  => admin_url( 'admin-ajax.php' ),
				'security' => wp_create_nonce( 'mcs-fields-action' ),
				'action'   => 'mcs_fields_action',
			)
		);
	}
}

/**
 * Enqueue styles for submissions and payments settings.
 */
function my_calendar_sub_styles() {
	global $mcs_version;
	if ( ! empty( $_GET['page'] ) ) {
		$p = sanitize_text_field( $_GET['page'] );
		if ( ( strpos( $p, 'my-calendar-submissions' ) !== false ) || 'my-calendar-payments' === $p || 'my-calendar-shortcodes' === $p ) {
			wp_enqueue_style( 'mc-styles', plugins_url( 'my-calendar/css/mc-styles.css' ), array(), $mcs_version );
			wp_enqueue_style( 'mcs-admin', plugins_url( 'css/mcs-admin.css', __FILE__ ), array(), $mcs_version );
		}
	}
	$post_events = ( is_array( get_option( 'mcs_post_event_types' ) ) ) ? get_option( 'mcs_post_event_types' ) : array();
	foreach ( $post_events as $post_type ) {
		global $current_screen;
		if ( 'post' === $current_screen->base && $current_screen->post_type === $post_type ) {
			wp_enqueue_style( 'my-calendar-pro-style' );
		}
	}
}

/**
 * Debug hook.
 *
 * @param Exception $e Exception.
 */
function mcs_log_error( $e ) {
	/**
	 * Perform an action if an error is logged. Only executed in payment handling. No default behavior.
	 *
	 * @hook mcs_log_error
	 *
	 * @param {Exception} $e Exception.
	 */
	do_action( 'mcs_log_error', $e );
}

add_action( 'init', 'mcs_register_styles' );
/**
 * Register styles for datepicker & submissions.
 */
function mcs_register_styles() {
	global $mcs_version;
	if ( SCRIPT_DEBUG && true === SCRIPT_DEBUG ) {
		$mcs_version = $mcs_version . uniqid();
	}
	wp_register_style( 'my-calendar-pro-style', plugins_url( 'css/mcs-styles.css', __FILE__ ), array( 'dashicons' ), $mcs_version );
	wp_register_style( 'my-calendar-responsive-base', apply_filters( 'mcs_responsive_base', plugins_url( 'css/mcs-responsive-base.css', __FILE__ ) ), array(), $mcs_version );
}

add_action( 'wp_enqueue_scripts', 'mcs_styles' );
/**
 * Enqueue My Calendar Pro stylesheet.
 */
function mcs_styles() {
	global $mcs_version;
	if ( SCRIPT_DEBUG && true === SCRIPT_DEBUG ) {
		$mcs_version = $mcs_version . uniqid();
	}
	wp_enqueue_style( 'my-calendar-pro-style' );
	// If the current My Calendar version is above 3.5, these don't need to be enqueued.
	$mc_version = mc_get_version();
	if ( version_compare( $mc_version, '3.5.0', '<=' ) ) {
		wp_enqueue_script( 'my-calendar-responsive', plugins_url( 'js/mcs-responsive.js', __FILE__ ), array( 'jquery' ), $mcs_version, true );
		if ( 'true' !== get_option( 'mcs_responsive_mode' ) ) {
			wp_enqueue_style( 'my-calendar-responsive-base' );
		}
	}
}

/**
 * Update payment database
 */
function mcs_update_database() {
	global $wpdb;
	$payments = 'CREATE TABLE ' . my_calendar_payments_table() . '  (
 `id` BIGINT( 20 ) NOT NULL AUTO_INCREMENT ,
 `item_number` BIGINT( 20 ) NOT NULL ,
 `event_id` BIGINT( 20 ) NOT NULL ,
 `quantity` BIGINT( 20 ) NOT NULL ,
 `total` BIGINT( 20 ) NOT NULL ,
 `hash` VARCHAR( 255 ) NOT NULL ,
 `txn_id` VARCHAR( 255 ) NOT NULL ,
 `price` FLOAT( 10, 2 ) NOT NULL ,
 `fee` FLOAT( 10, 2 ) NOT NULL ,
 `status` VARCHAR( 255 ) NOT NULL ,
 `transaction_date` DATETIME NOT NULL ,
 `first_name` VARCHAR( 255 ) NOT NULL ,
 `last_name` VARCHAR( 255 ) NOT NULL ,
 `payer_email` VARCHAR( 255 ) NOT NULL ,
 `gateway` VARCHAR( 255 ) NOT NULL ,
 `metadata` TEXT NOT NULL ,
 PRIMARY KEY  (id)
 ) ' . $wpdb->get_charset_collate();

	require_once ABSPATH . 'wp-admin/includes/upgrade.php';
	dbDelta( $payments );
}