<?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 );