cliff
2/23/2017 - 6:16 AM

Shortcode to display an edit link to each Venue (or Organizer) not used by any Event (All Events, not just Upcoming Events). For https://the

Shortcode to display an edit link to each Venue (or Organizer) not used by any Event (All Events, not just Upcoming Events). For https://theeventscalendar.com/support/forums/topic/removing-unlinked-venues-organizers/

<?php
/*
 * Shortcode to display an edit link to each Venue (or Organizer) not used by any Event (All Events, not just Upcoming Events). Also has a scary single line of commented-out code to then DELETE all such results (they don't even end up in the Trash). You've been warned!
 * Examples:
 *  Venues: [tribe_unused_posts] - https://cl.ly/0q441G1I3I05
 *  same as above: [tribe_unused_posts type=venues]
 *  Venues with Debug: [tribe_unused_posts debug=true] - https://cl.ly/2v0S2z420x0U
 *  Organizers: [tribe_unused_posts type=organizers] - https://cl.ly/1H3q2o1w2o3v
 *  Organizers with Debug: [tribe_unused_posts type=organizers debug=true] - https://cl.ly/0Y2s1k1n0T0R
 * Note: if multiple Organizers are assigned to an Event, there will be multiple _EventOrganizerID meta keys with single values, not a single _EventOrganizerID key with an array or comma-separated list of values.
 *
 * From https://gist.github.com/cliffordp/b9cde5ad57eecefca3bcd578fc5e6a61
 */
function tribe_unused_posts_logic( $atts ) {
	if ( ! class_exists( 'Tribe__Events__Main' ) ) {
		return false;
	}

	$defaults = array(
		'type'  => 'venues', // 'organizers'
		'debug' => 'false', // 'true'
	);

	$atts = shortcode_atts( $defaults, $atts, 'tribe_unused_posts' );

	global $wpdb;

	$tec_main = Tribe__Events__Main::instance();

	// $events_type = $tec_main::POSTTYPE;

	$type = strtolower( $atts['type'] );

	if ( 'organizers' == $type || 'organizer' == $type ) {
		$post_type = $tec_main::ORGANIZER_POST_TYPE;
		$meta_key = '_EventOrganizerID';
	} else {
		$post_type = $tec_main::VENUE_POST_TYPE;
		$meta_key = '_EventVenueID';
	}

	// Get all posts of the specified post type
	// https://codex.wordpress.org/Class_Reference/WP_Query
	$args = array(
		'post_type'         => $post_type,
		'posts_per_page'    => -1,
		'fields'            => 'ids',
		'order'             => 'ASC',
		'post_status'       => 'any', // Retrieves any status except those from post statuses with 'exclude_from_search' set to true (i.e. trash and auto-draft)
	);

	$ids_all = get_posts( $args );

	// Gets all database values for '_EventVenueID' or '_EventOrganizerID', whether or not they are valid, whether or not used by Events post type or another
	// https://codex.wordpress.org/wpdb
	$ids_in_use = $wpdb->get_col( $wpdb->prepare(
		"
		SELECT DISTINCT meta_value
		FROM $wpdb->postmeta
		WHERE meta_key = %s
		",
		$meta_key
	) );

	sort( $ids_in_use );

	// Get all valid post IDs of the specified post type that are not used in the database
	$ids_unused = array_diff( $ids_all, $ids_in_use );

	$output = '<div class="tribe_unused_posts-shortcode">';

	$debug = strtolower( $atts['debug'] );
	if ( 'true' == $debug ) {
		$output .= '<h3>Debug Info:</h3>';
		$output .= '<h4>All of post type</h4>';
		$output .= print_r( $ids_all, true );
		$output .= '<h4>All in use:</h4>';
		$output .= print_r( $ids_in_use, true );
		$output .= '<h4>Unused:</h4>';
		$output .= print_r( $ids_unused, true ) ;
		$output .= '<br>';
	}

	// short circuit if no Unused found -- doesn't mean there aren't invalid values in the database, such as '_EventOrganizerID' = 'abcd' (invalid since only integers should be in the db), or if invalid because set to zero, which isn't a valid post ID
	if ( empty( $ids_unused ) ) {
		$output .= sprintf( '<h3>We did not find any unused <strong>%s</strong>.</h3>', $post_type );
		$output .= '</div>';
		return $output;
	}

	// output the list of unused posts, along with their edit link, title, ID, and Post Status
	$output .= sprintf( '<h3>Unused <strong>%s</strong>:</h3><ul>', $post_type );

	foreach ( $ids_unused as $key => $value ) {
		$value = (int)$value;
		$output .= sprintf( '<li><a href="%s">%s - %d (%s)</a></li>', get_edit_post_link( $value ), get_the_title( $value ), $value, get_post_status( $value ) );
		// could optionally uncomment the following line of code to then DELETE each post of this type via https://developer.wordpress.org/reference/functions/wp_delete_post/
		// WARNING!!! // wp_delete_post( $value );
	}

	$output .= '</ul>';
	$output .= '</div>';

	return $output;
}

add_shortcode( 'tribe_unused_posts', 'tribe_unused_posts_logic' );