Source: my-calendar-hosts.php

<?php
/**
 * Custom Hosts. Replace the standard My Calendar hosts referencing user IDs with custom hosts.
 *
 * @category Hosts
 * @package  My Calendar Pro
 * @author   Joe Dolson
 * @license  GPLv2 or later
 * @link     https://www.joedolson.com/my-calendar-pro/
 */

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

add_action( 'admin_menu', 'mcs_hosts_outer_box' );
/**
 * Add metabox for event posting.
 *
 * @return void;
 */
function mcs_hosts_outer_box() {
	if ( 'true' === get_option( 'mcs_custom_hosts' ) ) {
		add_meta_box( 'mcs_hosts_fields', __( 'My Calendar Host', 'my-calendar-pro' ), 'mcs_hosts_inner_box', 'mc-hosts', 'side', 'high' );
	}
}

/**
 * Inner box
 */
function mcs_hosts_inner_box() {
	global $post;
	$phone = get_post_meta( $post->ID, '_mcs_host_phone', true );
	$url   = get_post_meta( $post->ID, '_mcs_host_url', true );
	$email = get_post_meta( $post->ID, '_mcs_host_email', true );
	$vis   = get_post_meta( $post->ID, '_mcs_host_visibility', true );
	$vis   = ( ! $vis ) ? 'private' : $vis;

	echo '<div class="mcs-host-fields mcs-hosts">
	<p>
		<label for="mcs_host_phone">' . esc_html__( 'Event Host Phone', 'my-calendar-pro' ) . '</label>
		<input type="tel" class="widefat" name="mcs_host_phone" id="mcs_host_phone" value="' . esc_attr( $phone ) . '" />
	</p>
	<p>
		<label for="mcs_host_url">' . esc_html__( 'Event Host Website', 'my-calendar-pro' ) . '</label>
		<input type="url" class="widefat" name="mcs_host_url" id="mcs_host_url" value="' . esc_attr( $url ) . '" />
	</p>
	<p>
		<label for="mcs_host_email">' . esc_html__( 'Event Host Email', 'my-calendar-pro' ) . '</label>
		<input type="email" class="widefat" name="mcs_host_email" id="mcs_host_email" value="' . esc_attr( $email ) . '" />
	</p>
	<fieldset>
		<legend>' . esc_html__( 'Contact Information visibility', 'my-calendar-pro' ) . '</legend>
		<ul>
			<li><input type="radio" name="mcs_host_visibility" id="mcs_host_visibility_public" value="public"' . checked( 'public', $vis, false ) . ' /> <label for="mcs_host_visibility_public">' . esc_html__( 'Public', 'my-calendar-pro' ) . '</label></li>
			<li><input type="radio" name="mcs_host_visibility" id="mcs_host_visibility_private" value="private"' . checked( 'private', $vis, false ) . ' /> <label for="mcs_host_visibility_private">' . esc_html__( 'Logged-in users', 'my-calendar-pro' ) . '</label></li>
			<li><input type="radio" name="mcs_host_visibility" id="mcs_host_visibility_hidden" value="hidden"' . checked( 'hidden', $vis, false ) . ' /> <label for="mcs_host_visibility_hidden">' . esc_html__( 'Hidden', 'my-calendar-pro' ) . '</label></li>
		</ul>
	</fieldset>
	</div>';
}

add_action( 'save_post', 'mcs_save_event_host', 15, 1 );
/**
 * Save custom fields for event host.
 *
 * @param int $post_id Post ID.
 *
 * @return int
 */
function mcs_save_event_host( $post_id ) {
	$is_valid_type = ( 'mc-hosts' === get_post_type( $post_id ) ) ? true : false;
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_id ) || ! $is_valid_type ) {

		return $post_id;
	}
	$phone = ( isset( $_POST['mcs_host_phone'] ) ) ? sanitize_text_field( $_POST['mcs_host_phone'] ) : '';
	$url   = ( isset( $_POST['mcs_host_url'] ) ) ? esc_url_raw( $_POST['mcs_host_url'] ) : '';
	$email = ( isset( $_POST['mcs_host_email'] ) ) ? sanitize_text_field( $_POST['mcs_host_email'] ) : '';
	$vis   = ( isset( $_POST['mcs_host_visibility'] ) && in_array( $_POST['mcs_host_visibility'], array( 'private', 'public', 'hidden' ), true ) ) ? $_POST['mcs_host_visibility'] : 'private';

	update_post_meta( $post_id, '_mcs_host_phone', $phone );
	update_post_meta( $post_id, '_mcs_host_url', $url );
	update_post_meta( $post_id, '_mcs_host_email', $email );
	update_post_meta( $post_id, '_mcs_host_visibility', $vis );

	return $post_id;
}

/**
 * Replace hosts selection with Hosts custom post type
 *
 * @param string $output Original source output.
 * @param int    $selected Selected ID.
 * @param string $group Current context.
 *
 * @return string
 */
function mcs_select_hosts( $output, $selected, $group ) {
	if ( 'true' !== get_option( 'mcs_custom_hosts' ) ) {
		return $output;
	}
	if ( 'hosts' === $group ) {
		$core_args = array(
			'post_type'   => 'mc-hosts',
			'numberposts' => -1,
			'post_status' => 'publish',
			'orderby'     => 'title',
			'order'       => 'ASC',
		);
		$core      = get_posts( $core_args );
		// If there are no custom hosts, return the original list.
		if ( empty( $core ) ) {
			return $output;
		}
		$core_orgs = '';
		$current   = '';
		foreach ( $core as $org ) {
			$post_ID    = $org->ID;
			$current    = ( (int) $post_ID === (int) $selected ) ? ' selected="selected"' : '';
			$post_title = $org->post_title;
			$core_orgs .= '<option value="' . $post_ID . '"' . $current . '>' . esc_html( $post_title ) . '</option>';
		}

		// Generate select list with custom output.
		$output = '	<option value="">' . __( 'Select a host', 'my-calendar-pro' ) . '</option>' . $core_orgs;
	}

	return $output;
}
add_filter( 'mc_custom_user_select', 'mcs_select_hosts', 10, 3 );

/**
 * Insert custom event hosts setting on misc settings tab.
 *
 * @param array $fields Miscellaneous settings fields.
 *
 * @return array
 */
function mcs_hosts_setting( $fields ) {
	$fields['hosts'] = array(
		'field_label'       => __( 'Replace default event hosts with custom posts.', 'my-calendar-pro' ),
		'field_notes'       => __( 'By default, My Calendar assigns hosts from your users list. Enable this option to use a custom post type instead.', 'my-calendar-pro' ),
		'field_type'        => 'checkbox',
		'field_options'     => 'true',
		'id'                => 'custom_hosts',
		'sanitize_callback' => 'sanitize_text_field',
		'field_default'     => ( 'true' === get_option( 'mcs_custom_hosts', 'false' ) ) ? 'true' : '',
	);

	if ( 'true' !== get_option( 'mcs_migrate_hosts' ) && 'true' === get_option( 'mcs_custom_hosts' ) ) {
		global $wpdb;
		$hosts                   = $wpdb->get_var( 'SELECT COUNT(DISTINCT event_host) FROM ' . my_calendar_table() ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$fields['migrate_hosts'] = array(
			'field_label'       => __( 'Migrate existing hosts to custom post type.', 'my-calendar-pro' ),
			// Translators: Number of unique hosts found.
			'field_notes'       => sprintf( _n( 'Migrate %d unique host to the host post type. This action is not reversible.', 'Migrate %d unique host to the host post type. This action is not reversible.', $hosts, 'my-calendar-pro' ), $hosts ),
			'field_type'        => 'checkbox',
			'field_options'     => 'true',
			'id'                => 'migrate_hosts',
			'sanitize_callback' => 'sanitize_text_field',
			'field_default'     => ( 'true' === get_option( 'mcs_migrate_hosts', 'false' ) ) ? 'true' : '',
		);
	}

	if ( 'true' === get_option( 'mcs_migrate_hosts' ) ) {
		mcs_migrate_hosts();
		update_option( 'mcs_migrated_hosts', 'true' );
	}

	return $fields;
}
add_filter( 'mcs_miscellaneous_settings', 'mcs_hosts_setting', 10, 1 );

/**
 * Migrate hosts when enabled.
 */
function mcs_migrate_hosts() {
	global $wpdb;
	$hosts = $wpdb->get_results( 'SELECT DISTINCT event_host FROM ' . my_calendar_table() ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	foreach ( $hosts as $host ) {
		$user = get_user_by( 'ID', $host->event_host );
		if ( $user ) {
			$post = array(
				'post_type'   => 'mc-hosts',
				'post_title'  => $user->display_name,
				'post_status' => 'publish',
				'post_author' => $host->event_host,
			);
			// Insert new post & available meta.
			$host_id = wp_insert_post( $post );
			update_post_meta( $host_id, '_mcs_host_email', $user->user_email );
			update_post_meta( $host_id, '_mcs_host_url', $user->user_url );
			// Update event table.
			if ( $host_id ) {
				$wpdb->update(
					my_calendar_table(),
					array( 'event_host' => $host_id ),
					array( 'event_host' => $host->event_host ),
					'%d',
					'%d'
				);
			}
		}
	}
	// Translators: Number of unique hosts imported.
	echo '<div class="notice notice-updated"><p>' . esc_html( sprintf( _n( '%d host imported. Events updated.', '%d hosts imported. Events updated.', count( $hosts ), 'my-calendar-pro' ), count( $hosts ) ) ) . '</p></div>';
}

/**
 * Filter theme content to display My Calendar host data.
 *
 * @param string $content Post content.
 *
 * @return string
 */
function mcs_display_host_details( $content ) {
	if ( is_singular( 'mc-hosts' ) && in_the_loop() && is_main_query() ) {
		global $post;
		$host = $post;
		$args = array(
			'host'     => get_the_ID(),
			'type'     => 'events',
			'after'    => 5,
			'before'   => 0,
			'fallback' => __( 'No events currently scheduled.', 'my-calendar-pro' ),
		);
		/**
		 * Filter the arguments used to generate upcoming events for a host. Default ['host' => $post_ID, 'type' => 'events', 'after' => 5, 'before' => 0, 'fallback' => 'No events currently scheduled.'].
		 *
		 * @hook mcs_display_host_events
		 *
		 * @param {array}  $args Array of upcoming events arguments.
		 * @param {object} $host Host post object.
		 *
		 * @return {array}
		 */
		$args    = apply_filters( 'mcs_display_host_events', $args, $host );
		$events  = my_calendar_upcoming_events( $args );
		$data    = array(
			'host'   => $host,
			'events' => $events,
		);
		$details = mc_load_template( 'host/single', $data );
		if ( $details ) {
			$content = $details;
		} else {
			$content = '
<div class="mc-view-host">
	<div class="mc-view-host-info">
		<div class="mc-host-card">' . mcs_host_template( $host ) . '</div>
		<div class="mc-host-content">' . $content . '</div>
	</div>
	<div class="mc-host-upcoming"><h2>' . __( 'Upcoming Events', 'my-calendar-pro' ) . '</h2>' . $events . '</div>
</div>';
			/**
			 * Filter the HTML output for single host's details.
			 *
			 * @hook mcs_host_output
			 *
			 * @param {string} $content Full HTML output.
			 * @param {object} $host Host post object.
			 *
			 * @return {string}
			 */
			$content = apply_filters( 'mcs_host_output', $content, $host );
		}
	}

	return $content;
}
add_filter( 'the_content', 'mcs_display_host_details' );

/**
 * Custom template function for host layout.
 *
 * @param object $host Post object for a host.
 *
 * @return string
 */
function mcs_host_template( $host ) {
	$type        = 'host';
	$avatar      = ( '' === get_the_post_thumbnail( $host ) ) ? get_avatar( get_post_meta( $host->ID, '_mcs_host_email', true ) ) : get_the_post_thumbnail( $host );
	$permissions = get_post_meta( $host->ID, '_mcs_host_visibility', true );
	$phone       = get_post_meta( $host->ID, '_mcs_host_phone', true );
	$email       = get_post_meta( $host->ID, '_mcs_host_email', true );
	$url         = get_post_meta( $host->ID, '_mcs_host_url', true );

	$contact_card  = ( '' !== $phone ) ? '<li class="mcs-host-phone">' . esc_html( $phone ) . '</li>' : '';
	$contact_card .= ( '' !== $email ) ? '<li class="mcs-host-email"><a href="mailto:' . esc_attr( $email ) . '">' . esc_html( $email ) . '</a></li>' : '';
	$public        = ( '' !== $phone ) ? '<li class="mcs-host-url"><a href="' . esc_url( $url ) . '">' . __( 'Website', 'my-calendar-pro' ) . '</a></li>' : '';

	switch ( $permissions ) {
		case 'public':
			$contact = $contact_card . $public;
			break;
		case 'private':
			$contact = ( is_user_logged_in() ) ? $contact_card . $public : $public;
			break;
		case 'hidden':
			$contact = $public;
			break;
	}

	$card = ( '' === $contact ) ? '' : '<ul class="host-' . $type . '">' . $contact . "</ul>\n";
	$card = '	<div class="mc-' . $type . '-card">' . $avatar . $card . '</div>';

	return $card;
}

/**
 * Import organizers from Tribe Events to My Calendar hosts.
 *
 * @param int $tribe_event Tribe Event Post ID.
 * @param int $event_id My Calendar event.
 *
 * @return int|bool
 */
function mcs_import_organizers_from_tribe( $tribe_event, $event_id ) {
	if ( 'true' === get_option( 'mcs_custom_hosts' ) ) {
		$organizer = get_post_meta( $tribe_event, '_EventOrganizerID', true );
		if ( ! $organizer ) {
			return;
		}
		$imported = get_post_meta( $organizer, '_mc_host_imported', true );
		if ( $imported ) {
			mc_update_event( 'event_host', $imported, $event_id, '%d' );

			return $imported;
		}
		$host   = get_post( $organizer );
		$name   = $host->post_title;
		$status = get_post_status( $organizer );
		$author = $host->post_author;
		$phone  = get_post_meta( $organizer, '_OrganizerPhone', true );
		$email  = get_post_meta( $organizer, '_OrganizerEmail', true );
		$url    = get_post_meta( $organizer, '_OrganizerWebsite', true );

		$post = array(
			'post_type'   => 'mc-hosts',
			'post_title'  => $name,
			'post_status' => $status,
			'post_author' => $author,
		);

		$host_id = wp_insert_post( $post );

		update_post_meta( $organizer, '_mc_host_imported', $host_id );
		update_post_meta( $host_id, '_mcs_host_phone', $phone );
		update_post_meta( $host_id, '_mcs_host_email', $email );
		update_post_meta( $host_id, '_mcs_host_url', $url );
		update_post_meta( $host_id, '_mc_host_visibility', '2' );

		mc_update_event( 'event_host', $host_id, $event_id, '%d' );
	}
}
add_action( 'my_calendar_imported_to_tribe', 'mcs_import_organizers_from_tribe', 10, 2 );

/**
 * Add option to enable custom hosts before importing if not enabled.
 *
 * @param string $output HTML output for custom fields.
 * @param string $source Event source name.
 *
 * @return string
 */
function mcs_custom_hosts_before_importing( $output, $source ) {
	if ( 'true' !== get_option( 'mcs_custom_hosts' ) && 'tribe' === $source ) {
		$output .= '<p><input type="checkbox" value="true" name="mcs_import_organizers" id="mcs_import_organizers"> <label for="mcs_import_organizers">' . __( 'Enable the My Calendar Pro Hosts post type and import Organizers as Hosts.', 'my-calendar-pro' ) . '</label></p>';
	}

	return $output;
}
add_filter( 'mc_importer_custom_fields', 'mcs_custom_hosts_before_importing', 10, 2 );

/**
 * Enable custom hosts before importing if option checked.
 *
 * @param string $source Migration source.
 */
function mcs_enable_custom_hosts_before_importing( $source ) {
	if ( 'tribe' === $source && isset( $_POST['mcs_import_organizers'] ) && 'true' === $_POST['mcs_import_organizers'] ) {
		update_option( 'mcs_custom_hosts', 'true' );
	}
}
add_filter( 'mc_handle_importer_custom_fields', 'mcs_enable_custom_hosts_before_importing', 10, 1 );