Skip to content

Instantly share code, notes, and snippets.

@jbrinley
Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbrinley/10933420 to your computer and use it in GitHub Desktop.
Save jbrinley/10933420 to your computer and use it in GitHub Desktop.
<?php
/*
Plugin Name: The Events Calendar - Cleanup Recurrence Duplicates
Description: Some users upgrading from an earlier version of Events Calendar PRO may, in rare circumstances, end up with duplicates of recurring events.
Version: 3.5
Author: Modern Tribe, Inc.
Author URI: http://tri.be?ref=tec-plugin
Text Domain: tribe-events-calendar-recurrence-cleanup
License: GPLv2 or later
*/
if ( !class_exists('TribeEventsPro_DuplicateRecurringEventCleanup') ) {
class TribeEventsPro_DuplicateRecurringEventCleanup {
/** @var TribeEventsPro_DuplicateRecurringEventCleanup */
private static $instance = NULL;
public static function instance() {
if ( empty(self::$instance) ) {
self::$instance = new self();
}
return self::$instance;
}
public static function init() {
$self = self::instance();
if ( $self->is_valid_install() ) {
$self->add_hooks();
}
}
private function is_valid_install() {
if ( class_exists('TribeEventsPro') && defined('TribeEventsPro::VERSION') ) {
if ( version_compare(TribeEventsPro::VERSION, '3.5') && class_exists( 'TribeEventsPro_RecurrenceInstance' ) ) {
return TRUE;
}
}
return FALSE;
}
private function add_hooks() {
add_filter( 'tribe_settings_tab_fields', array( $this, 'add_seetings_tab_fields' ), 10, 2 );
add_action( 'load-tribe_events_page_tribe-events-calendar', array( $this, 'listen_for_cleanup_button' ), 10, 0 );
}
public function add_seetings_tab_fields( $fields, $tab ) {
switch ( $tab ) {
case 'general':
$fields = TribeEvents::array_insert_after_key( 'amalgamateDuplicates', $fields, array(
'amalgamateRecurrenceDuplicates' => array(
'type' => 'html',
'html' => '<fieldset class="tribe-field tribe-field-html"><legend>'.__('Duplicate Recurring Events', 'tribe-events-calendar-recurrence-cleanup').'</legend><div class="tribe-field-wrap">'.$this->cleanup_button(__('Merge Duplicate Recurring Events', 'tribe-events-calendar-recurrence-cleanup')).'<p class="tribe-field-indent description">'.__('Some users upgrading from an earlier version of Events Calendar PRO may, in rare circumstances, end up with duplicates of recurring events. Press this button to clean up those duplicate events.', 'tribe-events-calendar-recurrence-cleanup').'</p></div></fieldset><div class="clear"></div>',
),
) );
break;
}
return $fields;
}
private function cleanup_button( $text = '' ) {
$text = $text?$text:__('Merge Duplicate Recurring Events', 'tribe-events-calendar-recurrence-cleanup');
$html = '<a href="%s" class="button">%s</a>';
$settings = TribeSettings::instance();
// get the base settings page url
$url = apply_filters( 'tribe_settings_url', add_query_arg( array( 'post_type' => TribeEvents::POSTTYPE, 'page' => $settings->adminSlug ), admin_url( 'edit.php' ) ) );
$url = add_query_arg(array('recurrenceCleanup' => '1'), $url);
$url = wp_nonce_url($url, 'recurrenceCleanup');
$html = sprintf($html, $url, $text);
return $html;
}
public function listen_for_cleanup_button() {
if ( empty($_REQUEST['recurrenceCleanup']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'recurrenceCleanup') ) {
return;
}
$more = $this->do_cleanup();
if ( $more ) {
$this->trigger_reload();
} else {
$this->redirect_to_settings_page();
}
}
protected function trigger_reload() {
$url = $_SERVER['REQUEST_URI'];
$redirect = '<script type="text/javascript">';
$redirect .= 'window.location.href="'.$url.'";';
$redirect .= '</script>';
$redirect .= '<noscript>';
$redirect .= '<meta http-equiv="refresh" content="0;url='.$url.'" />';
$redirect .= '</noscript>';
wp_die(__('Cleaning up events. This may take a while. Please do not close your browser window while cleanup is in progress.', 'tribe-events-calendar-recurrence-cleanup').$redirect, __('Cleaning up events', 'tribe-events-calendar-recurrence-cleanup'), array('response' => 200) );
exit();
}
protected function redirect_to_settings_page() {
// redirect to base settings page
$settings = TribeSettings::instance();
$url = apply_filters( 'tribe_settings_url', add_query_arg( array( 'post_type' => TribeEvents::POSTTYPE, 'page' => $settings->adminSlug ), admin_url( 'edit.php' ) ) );
wp_redirect($url);
exit();
}
protected function do_cleanup() {
TribeEventsRecurrenceMeta::get_scheduler()->remove_hooks();
$third_level_event_ids = $this->get_third_level_event_ids();
if ( !empty($third_level_event_ids) ) {
foreach ( $third_level_event_ids as $eid ) {
$this->remove_third_level_event($eid);
}
return TRUE;
}
$duplicate_meta_ids = $this->get_duplicate_meta_ids();
if ( !empty($duplicate_meta_ids) ) {
foreach ( $duplicate_meta_ids as $eid ) {
$this->remove_duplicate_meta($eid);
}
}
$duplicate_event_ids = $this->get_duplicate_event_ids();
if ( !empty($duplicate_event_ids) ) {
foreach ( $duplicate_event_ids as $eid ) {
$this->cleanup_event($eid);
}
return TRUE;
}
return FALSE;
}
private function get_duplicate_event_ids() {
global $wpdb;
$sql = "SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} m ON p.ID=m.post_id AND m.meta_key='_EventStartDate' WHERE p.post_parent <> 0 AND p.post_status <> 'trash' GROUP BY p.post_parent, m.meta_value HAVING COUNT(*) > 1";
$duplicate_instance_ids = $wpdb->get_col($sql);
if ( empty($duplicate_instance_ids) ) {
return array();
}
$duplicate_string = implode(',', $duplicate_instance_ids);
$parent_sql = "SELECT DISTINCT post_parent FROM {$wpdb->posts} p WHERE p.ID IN ($duplicate_string) LIMIT 10";
$result = $wpdb->get_col($parent_sql);
return $result;
}
public function cleanup_event( $event_id ) {
TribeEventsRecurrenceMeta::saveEvents($event_id);
}
private function get_third_level_event_ids() {
global $wpdb;
$sql = "SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->posts} p2 ON p.post_parent=p2.ID WHERE p.post_parent <> 0 AND p2.post_parent <> 0 LIMIT 10";
return $wpdb->get_col($sql);
}
public function remove_third_level_event( $event_id ) {
global $wpdb;
$children = $wpdb->get_col($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_parent=%d", $event_id));
foreach ( $children as $child ) {
$this->remove_third_level_event( $child );
}
wp_delete_post( $event_id, TRUE );
}
private function get_duplicate_meta_ids() {
global $wpdb;
$sql = "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_EventStartDate' GROUP BY post_id HAVING COUNT(*) > 1 LIMIT 100";
return $wpdb->get_col($sql);
}
public function remove_duplicate_meta( $event_id ) {
$meta = get_post_meta( $event_id, '_EventStartDate', FALSE );
if ( count($meta) > 1 ) {
delete_post_meta( $event_id, '_EventStartDate' );
add_post_meta( $event_id, '_EventStartDate', $meta[0] );
}
}
}
add_action('admin_init', array('TribeEventsPro_DuplicateRecurringEventCleanup', 'init'));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment