<?php
/**
* Migration tool: The Events Calendar.
*
* @category Import
* @package My Calendar
* @author Joe Dolson
* @license GPLv2 or later
* @link https://www.joedolson.com/my-calendar/
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Count remaining events from Tribe Events Calendar.
*
* @return int
*/
function mc_count_tribe_remaining() {
$args = array(
'post_type' => 'tribe_events',
'numberposts' => -1,
'fields' => 'ids',
'post_status' => 'any',
'meta_query' => array(
array(
'key' => '_mc_imported',
'compare' => 'NOT EXISTS',
),
),
);
$events = get_posts( $args );
if ( 0 === count( $events ) ) {
as_unschedule_all_actions( 'mc_import_tribe' );
}
return count( $events );
}
/**
* Import Tribe Events.
*
* @param int $limit Number of events to import.
*
* @return string Message about imported events.
*/
function mc_import_source_tribe_events( $limit = 25 ) {
global $wpdb;
$count = wp_count_posts( 'tribe_events' );
$message = '';
$total = 0;
foreach ( $count as $c ) {
$total = $total + (int) $c;
}
// Get selection of events not already imported.
$events = $wpdb->get_results( $wpdb->prepare( "SELECT $wpdb->posts.ID FROM $wpdb->posts LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '_mc_imported' ) WHERE 1=1 AND ( $wpdb->postmeta.post_id IS NULL ) AND $wpdb->posts.post_type = 'tribe_events' AND (($wpdb->posts.post_status <> 'trash' AND $wpdb->posts.post_status <> 'auto-draft')) GROUP BY $wpdb->posts.ID ORDER BY $wpdb->posts.post_parent ASC LIMIT 0, %d", $limit ) );
$ids = array();
$count = count( $events );
if ( 0 === $count ) {
update_option( 'mc_import_tribe_completed', 'true', 'no' );
} else {
foreach ( $events as $post ) {
$id = mc_import_source_tribe_event( $post->ID );
if ( $id ) {
$ids[] = $id;
}
}
$completed = count( $ids );
if ( false === as_has_scheduled_action( 'mc_import_tribe' ) ) {
as_schedule_recurring_action( strtotime( '+1 minutes' ), 60, 'mc_import_tribe', array(), 'my-calendar' );
}
// translators: 1) Number of events imported, 2) total number of events found.
$message = '<div class="notice notice-info"><p>' . sprintf( __( '%1$d events imported. %2$d remaining. Remaining events are being imported in the background. You can feel free to leave this page.', 'my-calendar' ), $completed, $total ) . '</p></div>';
}
return $message;
}
add_action( 'mc_import_tribe', 'mc_import_source_tribe_events' );
/**
* Suspend import process if completed.
*/
function mc_check_tribe_imports() {
if ( 'true' === get_option( 'mc_import_tribe_completed' ) ) {
as_unschedule_all_actions( 'mc_import_tribe' );
}
}
add_action( 'init', 'mc_check_tribe_imports' );
/**
* Import an event from Tribe Events Calendar.
*
* @param int $tribe_id ID of a tribe event post.
*
* @return bool|int False or new post ID.
*/
function mc_import_source_tribe_event( $tribe_id ) {
// If already imported, return false.
$imported = get_post_meta( $tribe_id, '_mc_imported', true );
if ( $imported ) {
return false;
}
$tribe_event = get_post( $tribe_id );
/**
* Filter imported event to customize what gets added to database. Return false to skip event.
*
* @hook mc_imported_event
*
* @param {array} $event Array of event data passed to `mc_check_data`.
*
* @return {array|false}
*/
$event = apply_filters( 'mc_imported_event_tribe', $tribe_event );
$parent = $event->post_parent;
if ( ! $parent ) {
// This is a full event, not a sub event in a recurring series.
$event = mc_format_tribe_event_for_import( $event );
if ( false === $event ) {
return;
}
$count = count( $event['event_begin'] );
for ( $i = 0; $i < $count; $i++ ) {
$check = mc_check_data( 'add', $event, 0, true );
$event_id = false;
if ( $check[0] ) {
$response = my_calendar_save( 'add', $check );
$event_id = $response['event_id'];
/**
* Perform an action after an event has been imported from Tribe Events Calendar to My Calendar.
*
* @hook my_calendar_event_imported_from_tribe
*
* @param {int} $tribe_id Post ID from Tribe Events.
* @param {int} $event_id Event ID from My Calendar.
* @param {int} $event_post Post ID for My Calendar event.
*/
do_action( 'my_calendar_event_imported_from_tribe', $tribe_id, $event_id, $response['event_post'] );
if ( ! empty( $event['event_image_id'] ) ) {
set_post_thumbnail( $response['event_post'], $event['event_image_id'] );
}
// Import tickets from Tribe Tickets to My Tickets.
mc_import_tribe_tickets( $tribe_id, $response['event_post'] );
update_post_meta( $tribe_id, '_mc_imported', $event_id );
}
}
} else {
// This is part of a recurring series; add to parent event.
$event = mc_format_tribe_event_for_import( $event, 'instance' );
$mc_event = get_post_meta( $parent, '_mc_imported', true );
$event['id'] = $mc_event;
// This isn't the same event ID; it's an instance ID. Only used for counting the imports, however.
$event_id = mc_insert_instance( $event );
// Mark post as imported.
update_post_meta( $tribe_id, '_mc_imported', $mc_event );
/**
* Perform an action after an occurrence has been imported from Tribe Events Calendar to My Calendar.
*
* @hook my_calendar_instance_imported_from_tribe
*
* @param {int} $tribe_id Post ID from Tribe Events.
* @param {int} $mc_event Event ID from My Calendar.
* @param {int} $parent Parent ID from Tribe.
*/
do_action( 'my_calendar_instance_imported_from_tribe', $tribe_id, $mc_event, $parent );
}
return $event_id;
}
/**
* Adapt a Tribe event to the My Calendar import structure.
*
* @param object $event WordPress Post from Tribe Events.
* @param string $type Type of return. 'event' or 'instance'.
*
* @return array Importable data for My Calendar depending on type.
*/
function mc_format_tribe_event_for_import( $event, $type = 'event' ) {
$terms = get_the_terms( $event, 'tribe_events_cat' );
if ( is_array( $terms ) ) {
foreach ( $terms as $term ) {
$cat_id = mc_category_by_name( $term->name );
if ( ! $cat_id ) {
$cat = array(
'category_name' => $term->name,
);
$cat_id = mc_create_category( $cat );
}
// if category does not exist, create.
$category_ids[] = $cat_id;
}
} else {
$category_ids[] = 1;
}
// If _EventRecurrence, create instance for each event. TODO
// Spawn collection of dates in array to be used in event_begin and event_end.
if ( 'instance' === $type ) {
$my_calendar_event = array(
'id' => '',
'event_date' => gmdate( 'Y-m-d', strtotime( get_post_meta( $event->ID, '_EventStartDate', true ) ) ),
'event_time' => gmdate( 'H:i:00', strtotime( get_post_meta( $event->ID, '_EventStartDate', true ) ) ),
'event_end' => gmdate( 'Y-m-d', strtotime( get_post_meta( $event->ID, '_EventEndDate', true ) ) ),
'event_endtime' => gmdate( 'H:i:00', strtotime( get_post_meta( $event->ID, '_EventEndDate', true ) ) ),
'group' => '', // No correlation in Tribe.
);
} else {
$my_calendar_event = array(
// Event data.
'event_title' => $event->post_title,
'event_begin' => array( gmdate( 'Y-m-d', strtotime( get_post_meta( $event->ID, '_EventStartDate', true ) ) ) ),
'event_end' => array( gmdate( 'Y-m-d', strtotime( get_post_meta( $event->ID, '_EventEndDate', true ) ) ) ),
'event_time' => array( gmdate( 'H:i:00', strtotime( get_post_meta( $event->ID, '_EventStartDate', true ) ) ) ),
'event_endtime' => array( gmdate( 'H:i:00', strtotime( get_post_meta( $event->ID, '_EventEndDate', true ) ) ) ),
'content' => $event->post_content,
'event_short' => $event->post_excerpt,
'event_link' => get_post_meta( $event->ID, '_EventURL', true ),
'event_image' => get_the_post_thumbnail_url( $event->ID ),
'event_image_id' => get_post_thumbnail_id( $event->ID ),
'event_allday' => ( 'yes' === get_post_meta( $event->ID, '_EventAllDay', true ) ) ? '1' : '0',
'event_author' => $event->post_author,
'event_approved' => mc_convert_post_status_to_approval( $event->post_status ),
'event_category' => $category_ids,
// Event organizers are only supported in My Calendar Pro.
'event_host' => $event->post_author,
// meta data.
'event_added' => $event->post_date,
'event_nonce_name' => wp_create_nonce( 'event_nonce' ),
'event_group_id' => mc_group_id(),
);
$venue_id = get_post_meta( $event->ID, '_EventVenueID', true );
if ( $venue_id && 'tribe_venue' === get_post_type( $venue_id ) ) {
$location_id = get_post_meta( $venue_id, '_mc_tribe_location_id', true );
if ( ! $location_id ) {
$location_id = mc_import_tribe_location( $venue_id );
}
$my_calendar_event['preset_location'] = $location_id;
}
}
/**
* Filter event to be inserted from Tribe.
*
* @hook mc_format_tribe_event_for_import
*
* @param {array} $my_calendar_event Array of data to be passed to mc_check_data.
* @param {object} $event Post object from tribe_events post type.
* @param {string} $type Type of data being returned; instance or event.
*
* @return {array}
*/
$my_calendar_event = apply_filters( 'mc_format_tribe_event_for_import', $my_calendar_event, $event, $type );
return $my_calendar_event;
}
/**
* Import a venue from Tribe to My Calendar.
*
* @param int $venue_id Post ID for a Tribe venue.
*
* @return int $location_id Location ID for a My Calendar location.
*/
function mc_import_tribe_location( $venue_id ) {
// This is a double check before inserting.
$check = get_post_meta( $venue_id, '_mc_tribe_location_id', true );
if ( is_numeric( $check ) ) {
return $check;
}
$state = ( get_post_meta( $venue_id, '_VenueState', true ) ) ? get_post_meta( $venue_id, '_VenueState', true ) : get_post_meta( $venue_id, '_VenueProvince', true );
$venue = get_post( $venue_id );
$add = array(
'location_label' => $venue->post_title,
'location_street' => get_post_meta( $venue_id, '_VenueAddress', true ),
'location_street2' => '',
'location_city' => get_post_meta( $venue_id, '_VenueCity', true ),
'location_state' => $state,
'location_postcode' => get_post_meta( $venue_id, '_VenueZip', true ),
'location_region' => '',
'location_country' => get_post_meta( $venue_id, '_VenueCountry', true ),
'location_url' => get_post_meta( $venue_id, '_VenueURL', true ),
'location_latitude' => '',
'location_longitude' => '',
'location_zoom' => 16,
'location_phone' => get_post_meta( $venue_id, '_VenuePhone', true ),
'location_phone2' => '',
'location_access' => '',
);
$location_id = mc_insert_location( $add );
// Ensure the location post is created and get that ID.
$post_id = apply_filters( 'mc_save_location', $location_id, $add, array() );
if ( is_numeric( $location_id ) ) {
// Only set the venue relationship if location ID is set.
update_post_meta( $venue_id, '_mc_tribe_location_id', $location_id );
// Set featured image for location.
$featured_image_id = get_post_thumbnail_id( $venue_id );
if ( $featured_image_id ) {
$location_post = ( $post_id ) ? $post_id : mc_get_location_post( $location_id );
set_post_thumbnail( $location_post, $featured_image_id );
}
// Set location post content to venue content.
$update_post = array(
'ID' => $location_post,
'post_content' => $venue->post_content,
);
wp_update_post( $update_post );
}
return $location_id;
}
/**
* Add tickets from Tribe when an event is added.
*
* @param int $tribe_id Post ID for a Tribe event.
* @param int $event_post Event post for a calendar event.
*/
function mc_import_tribe_tickets( $tribe_id, $event_post ) {
// If Event Tickets && My Tickets installed, migrate tickets data.
if ( function_exists( 'tribe_events_has_tickets' ) && function_exists( 'mt_create_payment' ) ) {
global $wpdb;
$tribe_tickets = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE meta_key = '_tribe_wooticket_for_event' AND meta_value = %d", $tribe_id ) );
// Handle creation of tickets on event post.
if ( is_array( $tribe_tickets ) && count( $tribe_tickets ) > 0 ) {
// Get post meta for this data.
$prices = array();
foreach ( $tribe_tickets as $ticket ) {
$ticket_id = $ticket->post_id;
$title = get_the_title( $ticket_id ); // Title is the label for ticket.
$title_key = sanitize_key( $title );
$sales = get_post_meta( $ticket_id, 'total_sales', true ); // Sales on this ticket.
$total = get_post_meta( $ticket_id, '_tribe_ticket_capacity', true ); // Number available.
$price = get_post_meta( $ticket_id, '_price', true ); // ticket price as int.
$end = get_post_meta( $ticket_id, '_ticket_end_date', true ); // ticket off sale date.
// Structure prices array.
$title_array = array(
'label' => $title,
'price' => $price,
'tickets' => $total,
'sold' => $sales,
'close' => strtotime( $end ),
);
/**
* Filter My Tickets pricing array for a single ticket.
*
* @hook mc_filter_price_array
*
* @param {array} $title_array Pricing array for one Tribe ticket.
* @param {int} $ticket_id Tribe ticket ID.
*
* @return {array}
*/
$title_array = apply_filters( 'mc_filter_price_array', $title_array, $ticket_id );
$prices[ $title_key ] = $title_array;
}
// Global My Calendar event data.
$mc_event_data = get_post_meta( $event_post, '_mc_event_data', true );
$mc_event_data['general_admission'] = ''; // Tribe events don't support general admission.
$mc_event_data['event_valid'] = ''; // Event validity only applies to general admissions.
$mc_event_data['expire_date'] = ''; // Expiration date for general admission.
update_post_meta( $event_post, '_mc_event_data', $mc_event_data );
// Set sales to expired if date in past.
$begin = strtotime( $mc_event_data['event_begin'] . ' ' . $mc_event_data['event_time'] );
if ( mt_date_comp( mt_date( 'Y-m-d H:i:s', $begin ), mt_date( 'Y-m-d H:i:s', mt_current_time() ) ) ) {
update_post_meta( $event_post, '_mt_event_expired', 'true' );
}
update_post_meta( $event_post, '_mc_event_date', $begin );
$registration_options = array(
'reg_expires' => 1,
'sales_type' => 'tickets',
'counting_method' => 'discrete',
'prices' => $prices,
'total' => 'inherit',
'multiple' => 'true',
);
/**
* Filter My Tickets profile data before saving.
*
* @hook mc_import_tribe_tickets_options
*
* @param {array} $registration_options Options data to save for new event.
* @param {int} $tribe_id Tribe event ID.
* @param {int} $ticket_id Tribe ticket ID.
* @param {int} $event_post My Calendar event post ID.
*
* @return {array}
*/
$registration_options = apply_filters( 'mc_import_tribe_tickets_options', $registration_options, $tribe_id, $ticket_id, $event_post );
update_post_meta( $event_post, '_mt_registration_options', $registration_options );
update_post_meta( $event_post, '_mt_sell_tickets', 'true' );
}
}
}