', $line_1, $line_2 ) );
}
/**
* Append the text about The Events Calendar to the feature box on the Help page
*
* @filter "tribe_help_pre_get_sections"
* @param Tribe__Admin__Help_Page $help The Help Page Instance
* @return void
*/
public function add_help_section_feature_box_content( $help ) {
$link = '' . esc_html__( 'New User Primer', 'the-events-calendar' ) . '';
$help->add_section_content( 'feature-box', sprintf( __( 'We are committed to helping make your calendar spectacular and have a wealth of resources available, including a handy %s to get your calendar up and running.', 'the-events-calendar' ), $link ) );
}
/**
* Append the text about The Events Calendar to the support section on the Help page
*
* @filter "tribe_help_pre_get_sections"
* @param Tribe__Admin__Help_Page $help The Help Page Instance
* @return void
*/
public function add_help_section_support_content( $help ) {
$help->add_section_content( 'support', '' . esc_html__( 'Support for The Events Calendar', 'the-events-calendar' ) . '', 15 );
$help->add_section_content( 'support', array(
sprintf( __( '%s: A thorough walkthrough of The Events Calendar and the settings that are available to you.', 'the-events-calendar' ), '' . esc_html__( 'Settings overview', 'the-events-calendar' ) . '' ),
sprintf( __( '%s: A complete look at the features you can expect to see right out of the box as well as how to use them.', 'the-events-calendar' ), '' . esc_html__( 'Features overview', 'the-events-calendar' ) . '' ),
sprintf( __( '%s: Our most comprehensive outline for customizing the calendar to suit your needs, including custom layouts and styles.', 'the-events-calendar' ), '' . esc_html__( 'Themer’s Guide', 'the-events-calendar' ) . '' ),
sprintf( __( '%s: An overview of the default templates and styles that are included in the plugin, as well as how to change them.', 'the-events-calendar' ), '' . esc_html__( 'Using stylesheets and page templates', 'the-events-calendar' ) . '' ),
sprintf( __( '%s: Do you see an issue with your calendar? Go here first to find where it’s coming from and how to fix it.', 'the-events-calendar' ), '' . esc_html__( 'Troubleshooting common problems', 'the-events-calendar' ) . '' ),
sprintf( __( '%s: Code and guides for customizing your calendar in useful and interesting ways.', 'the-events-calendar' ), '' . esc_html__( 'Customizing the Events plugins', 'the-events-calendar' ) . '' ),
), 15 );
}
/**
* Append the text about The Events Calendar to the Extra Help section on the Help page
*
* @filter "tribe_help_pre_get_sections"
* @param Tribe__Admin__Help_Page $help The Help Page Instance
* @return void
*/
public function add_help_section_extra_content( $help ) {
if ( ! $help->is_active( array( 'events-calendar-pro', 'event-tickets-plus' ) ) && $help->is_active( 'event-tickets' ) ) {
$link_tec = '' . esc_html__( 'The Events Calendar', 'the-events-calendar' ) . '';
$link_et = '' . esc_html__( 'Events Tickets', 'the-events-calendar' ) . '';
$help->add_section_content( 'extra-help', sprintf( __( 'If you have tried the above steps and are still having trouble, you can post a new thread to our WordPress.org forums for %1$s or %2$s. Our support staff monitors these forums once a week and would be happy to assist you there. ', 'the-events-calendar' ), $link_tec, $link_et ), 20 );
$link = '' . esc_html__( 'premium support on our website', 'the-events-calendar' ) . '';
$help->add_section_content( 'extra-help', sprintf( __( 'Looking for more immediate support? We offer %s with the purchase of any of our premium plugins. Pick up a license and you can post there directly and expect a response within 24-48 hours during weekdays', 'the-events-calendar' ), $link ), 20 );
} elseif ( ! $help->is_active( array( 'events-calendar-pro', 'event-tickets' ) ) ) {
$link = '' . esc_html__( 'open-source forum on WordPress.org', 'the-events-calendar' ) . '';
$help->add_section_content( 'extra-help', sprintf( __( 'If you have tried the above steps and are still having trouble, you can post a new thread to our %s. Our support staff monitors these forums once a week and would be happy to assist you there.', 'the-events-calendar' ), $link ), 20 );
$link_forum = '' . esc_html__( 'premium support on our website', 'the-events-calendar' ) . '';
$link_plus = '' . esc_html__( 'Events Calendar PRO', 'the-events-calendar' ) . '';
$help->add_section_content( 'extra-help', sprintf( __( 'Looking for more immediate support? We offer %1$s with the purchase of any of our premium plugins (like %2$s). Pick up a license and you can post there directly and expect a response within 24-48 hours during weekdays.', 'the-events-calendar' ), $link_forum, $link_plus ), 20 );
} else {
$link = '' . esc_html__( 'post a thread', 'the-events-calendar' ) . '';
$help->add_section_content( 'extra-help', sprintf( __( 'If you have a valid license for one of our paid plugins, you can %s in our premium support forums. Our support team monitors the forums and will respond to your thread within 24-48 hours (during the week).', 'the-events-calendar' ), $link ), 20 );
}
}
/**
* Load the ical template tags
* Loaded late due to potential upgrade conflict since moving them from pro
*
* @TODO move this require to be with the rest of the template tag includes in 3.9
*/
public function init_ical() {
//iCal
Tribe__Events__iCal::init();
require_once $this->plugin_path . 'src/functions/template-tags/ical.php';
}
/**
* Allow users to specify their own plural label for Venues
*
* @return string
*/
public function get_venue_label_plural() {
return Tribe__Events__Venue::instance()->get_venue_label_plural();
}
/**
* Allow users to specify their own singular label for Venues
* @return string
*/
public function get_venue_label_singular() {
return Tribe__Events__Venue::instance()->get_venue_label_singular();
}
/**
* Allow users to specify their own plural label for Organizers
* @return string
*/
public function get_organizer_label_plural() {
return Tribe__Events__Organizer::instance()->get_organizer_label_plural();
}
/**
* Allow users to specify their own singular label for Organizers
* @return string
*/
public function get_organizer_label_singular() {
return Tribe__Events__Organizer::instance()->get_organizer_label_singular();
}
/**
* Allow users to specify their own plural label for Events
* @return string
*/
public function get_event_label_plural() {
return apply_filters( 'tribe_event_label_plural', esc_html__( 'Events', 'the-events-calendar' ) );
}
/**
* Allow users to specify their own singular label for Events
* @return string
*/
public function get_event_label_singular() {
return apply_filters( 'tribe_event_label_singular', esc_html__( 'Event', 'the-events-calendar' ) );
}
/**
* Load the day view template tags
* Loaded late due to potential upgrade conflict since moving them from pro
* @TODO move this require to be with the rest of the template tag includes in 3.9
*/
public function init_day_view() {
// load day view functions
require_once $this->plugin_path . 'src/functions/template-tags/day.php';
}
/**
* Runs on the "wp" action. Inspects the main query object and if it relates to an events
* query makes a decision to add a noindex meta tag based on whether events were returned
* in the query results or not.
*
* Disabling this behaviour always is possible with:
*
* add_filter( 'tribe_events_add_no_index_meta', '__return_false' );
*
* Enabling it for all event views is possible with:
*
* add_filter( 'tribe_events_add_no_index_meta', '__return_true' );
*/
public function issue_noindex() {
global $wp_query;
if ( empty( $wp_query->tribe_is_event_query ) ) {
return;
}
// By default, we add a noindex tag for all month view requests and any other
// event views that are devoid of events
$event_display = get_query_var( 'eventDisplay' );
$add_noindex = ( ! $wp_query->have_posts() || 'month' === $event_display );
/**
* Determines if a noindex meta tag will be set for the current event view.
*
* @var bool $add_noindex
*/
$add_noindex = apply_filters( 'tribe_events_add_no_index_meta', $add_noindex );
if ( $add_noindex ) {
add_action( 'wp_head', array( $this, 'print_noindex_meta' ) );
}
}
/**
* Prints a "noindex,follow" robots tag.
*/
public function print_noindex_meta() {
echo ' ' . "\n";
}
/**
* Run on applied action init
*/
public function init() {
// Start the integrations manager
Tribe__Events__Integrations__Manager::instance()->load_integrations();
$rewrite = Tribe__Events__Rewrite::instance();
$venue = Tribe__Events__Venue::instance();
$organizer = Tribe__Events__Organizer::instance();
$this->postVenueTypeArgs = $venue->post_type_args;
$this->postOrganizerTypeArgs = $organizer->post_type_args;
$this->pluginName = $this->plugin_name = esc_html__( 'The Events Calendar', 'the-events-calendar' );
$this->rewriteSlug = $this->getRewriteSlug();
$this->rewriteSlugSingular = $this->getRewriteSlugSingular();
$this->category_slug = $this->get_category_slug();
$this->tag_slug = $this->get_tag_slug();
$this->taxRewriteSlug = $this->rewriteSlug . '/' . $this->category_slug;
$this->tagRewriteSlug = $this->rewriteSlug . '/' . $this->tag_slug;
$this->monthSlug = sanitize_title( __( 'month', 'the-events-calendar' ) );
$this->listSlug = sanitize_title( __( 'list', 'the-events-calendar' ) );
$this->upcomingSlug = sanitize_title( __( 'upcoming', 'the-events-calendar' ) );
$this->pastSlug = sanitize_title( __( 'past', 'the-events-calendar' ) );
$this->daySlug = sanitize_title( __( 'day', 'the-events-calendar' ) );
$this->todaySlug = sanitize_title( __( 'today', 'the-events-calendar' ) );
$this->singular_venue_label = $this->get_venue_label_singular();
$this->plural_venue_label = $this->get_venue_label_plural();
$this->singular_organizer_label = $this->get_organizer_label_singular();
$this->plural_organizer_label = $this->get_organizer_label_plural();
$this->singular_event_label = $this->get_event_label_singular();
$this->plural_event_label = $this->get_event_label_plural();
$this->singular_event_label_lowercase = tribe_get_event_label_singular_lowercase();
$this->plural_event_label_lowercase = tribe_get_event_label_plural_lowercase();
$this->postTypeArgs['rewrite']['slug'] = $rewrite->prepare_slug( $this->rewriteSlugSingular, self::POSTTYPE, false );
$this->currentDay = '';
$this->errors = '';
$this->default_values = apply_filters( 'tribe_events_default_value_strategy', new Tribe__Events__Default_Values() );
Tribe__Events__Query::init();
Tribe__Events__Backcompat::init();
Tribe__Credits::init();
Tribe__Events__Timezones::init();
$this->registerPostType();
Tribe__Debug::debug( sprintf( esc_html__( 'Initializing Tribe Events on %s', 'the-events-calendar' ), date( 'M, jS \a\t h:m:s a' ) ) );
$this->maybeSetTECVersion();
}
/**
* Initializes any admin-specific code (expects to be called when admin_init fires).
*/
public function admin_init() {
global $pagenow;
$this->timezone_settings = new Tribe__Events__Admin__Timezone_Settings;
// Right now it only makes sense to add these extra upgrade notices within the plugins.php screen
if ( 'plugins.php' === $pagenow ) {
new Tribe__Admin__Notice__Plugin_Upgrade_Notice(
self::VERSION,
$this->plugin_dir . 'the-events-calendar.php'
);
}
}
/**
* Set the Calendar Version in the options table if it's not already set.
*/
public function maybeSetTECVersion() {
if ( version_compare( Tribe__Settings_Manager::get_option( 'latest_ecp_version' ), self::VERSION, '<' ) ) {
$previous_versions = Tribe__Settings_Manager::get_option( 'previous_ecp_versions' ) ? Tribe__Settings_Manager::get_option( 'previous_ecp_versions' ) : array();
$previous_versions[] = ( Tribe__Settings_Manager::get_option( 'latest_ecp_version' ) ) ? Tribe__Settings_Manager::get_option( 'latest_ecp_version' ) : '0';
Tribe__Settings_Manager::set_option( 'previous_ecp_versions', $previous_versions );
Tribe__Settings_Manager::set_option( 'latest_ecp_version', self::VERSION );
}
}
/**
* Check add-ons to make sure they are supported by currently running TEC version.
*/
public function checkAddOnCompatibility() {
// Variable for storing output to admin notices.
$output = '';
// Array to store any plugins that are out of date.
$out_of_date_addons = array();
// Array to store all addons and their required CORE versions.
$tec_addons_required_versions = array();
// Is Core the thing that is out of date?
$tec_out_of_date = false;
// Get the addon information.
$tec_addons_required_versions = (array) apply_filters( 'tribe_tec_addons', $tec_addons_required_versions );
// Foreach addon, make sure that it is compatible with current version of core.
foreach ( $tec_addons_required_versions as $plugin ) {
// we're not going to check addons that we can't
if ( empty( $plugin['required_version'] ) || empty( $plugin['current_version'] ) ) {
continue;
}
// check if TEC is out of date
if ( version_compare( $plugin['required_version'], self::VERSION, '>' ) ) {
$tec_out_of_date = true;
break;
}
// check if the add-on is out of date
if ( version_compare( $plugin['current_version'], self::MIN_ADDON_VERSION, '<' ) ) {
// don't throw notices for the 4.2 legacy versions of Facebook and iCal
if (
(
false !== strpos( $plugin['plugin_dir_file'], 'the-events-calendar-facebook-importer.php' )
|| false !== strpos( $plugin['plugin_dir_file'], 'the-events-calendar-ical-importer.php' )
)
&& version_compare( $plugin['current_version'], '4.2', '>=' )
) {
continue;
}
$out_of_date_addons[] = $plugin['plugin_name'] . ' ' . $plugin['current_version'];
}
}
// If Core is out of date, generate the proper message.
if ( $tec_out_of_date == true ) {
$plugin_short_path = basename( dirname( dirname( __FILE__ ) ) ) . '/the-events-calendar.php';
$upgrade_path = wp_nonce_url(
add_query_arg(
array(
'action' => 'upgrade-plugin',
'plugin' => $plugin_short_path,
), get_admin_url() . 'update.php'
), 'upgrade-plugin_' . $plugin_short_path
);
$output .= '
';
$output .= '
' . sprintf( esc_html__( 'Your version of The Events Calendar is not up-to-date with one of your The Events Calendar add-ons. Please %supdate now.%s', 'the-events-calendar' ), '', '' ) . '
';
$output .= '
';
} elseif ( ! empty( $out_of_date_addons ) ) {
// Otherwise, if the addons are out of date, generate the proper messaging.
$output .= '
' . sprintf( esc_html__( 'The following plugins are out of date: %1$s. All add-ons contain dependencies on The Events Calendar and will not function properly unless paired with the right version. %2$sLearn More%3$s.', 'the-events-calendar' ), '' . join( $out_of_date_addons, ', ' ) . '', "", '' ) . '
';
$output .= '
';
}
// Make sure only to show the message if the user has the permissions necessary.
if ( current_user_can( 'edit_plugins' ) ) {
echo apply_filters( 'tribe_add_on_compatibility_errors', $output );
}
}
/**
* Init the settings API and add a hook to add your own setting tabs (disused since 4.3,
* does nothing when called).
*
* @deprecated 4.3
*/
public function initOptions() {
_deprecated_function( __METHOD__, 4.3 );
}
/**
* Trigger is_404 on single event if no events are found
*/
public function template_redirect() {
global $wp_query;
// if JS is disabled, then we need to handle tribe bar submissions manually
if ( ! empty( $_POST['tribe-bar-view'] ) && ! empty( $_POST['submit-bar'] ) ) {
$this->handle_submit_bar_redirect( $_POST );
}
if ( $wp_query->tribe_is_event_query && self::instance()->displaying == 'single-event' && empty( $wp_query->posts ) ) {
$wp_query->is_404 = true;
}
}
/**
* handles tribe bar post submissions
*
* @param array $postdata Data from $_POST
*/
public function handle_submit_bar_redirect( $postdata ) {
$url = $postdata['tribe-bar-view'];
$url_parts = parse_url( $url );
$safe_domains = $this->safe_redirect_domains();
// if the site isn't a safe domain, spoofing is probably being attempted. Bail
if ( ! in_array( $url_parts['host'], $safe_domains ) ) {
return;
}
foreach ( $postdata as $key => $value ) {
if ( 'submit-bar' === $key || 'tribe-bar-view' === $key ) {
continue;
}
$url = add_query_arg( $key, $value, $url );
}
wp_redirect( esc_url_raw( $url ) );
die;
}//end handle_submit_bar_redirect
/**
* Provides a list of URLs that are considered safe for redirecting
*/
public function safe_redirect_domains() {
$home = home_url( '/' );
$site = site_url( '/' );
$domains = array();
$domains[] = parse_url( $home, PHP_URL_HOST );
$domains[] = parse_url( $site, PHP_URL_HOST );
/**
* Filters the list of safe redirect domains
*
* @var array Array of domains that are safe to redirect to
*/
$domains = apply_filters( 'tribe_events_safe_redirect_domains', $domains );
$domains = array_unique( $domains );
return $domains;
}
/**
* Create setting tabs
*/
public function doSettingTabs() {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::do_setting_tabs' );
Tribe__Settings_Manager::instance()->do_setting_tabs();
}
/**
* Initialize the addons api settings tab
*/
public function do_addons_api_settings_tab() {
include_once $this->plugin_path . 'src/admin-views/tribe-options-addons-api.php';
}
/**
* Create the help tab
*/
public function doHelpTab() {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::do_help_tab' );
Tribe__Settings_Manager::instance()->do_help_tab();
}
/**
* Updates the start/end time on all day events to match the EOD cutoff
*
* @see 'update_option_'.Tribe__Main::OPTIONNAME
*/
public function fix_all_day_events( $old_value, $new_value ) {
// avoid notices for missing indices
$default_value = '00:00';
if ( empty( $old_value['multiDayCutoff'] ) ) {
$old_value['multiDayCutoff'] = $default_value;
}
if ( empty( $new_value['multiDayCutoff'] ) ) {
$new_value['multiDayCutoff'] = $default_value;
}
if ( $old_value['multiDayCutoff'] == $new_value['multiDayCutoff'] ) {
// we only want to continue if the EOD cutoff was changed
return;
}
global $wpdb;
$event_start_time = $new_value['multiDayCutoff'] . ':00';
// mysql query to set the start times on all day events to the EOD cutoff
// this will fix all day events with any start time
$fix_start_dates = $wpdb->prepare( "UPDATE $wpdb->postmeta AS pm1
INNER JOIN $wpdb->postmeta pm2
ON (pm1.post_id = pm2.post_id AND pm2.meta_key = '_EventAllDay' AND pm2.`meta_value` = 'yes')
SET pm1.meta_value = CONCAT(DATE(pm1.meta_value), ' ', %s)
WHERE pm1.meta_key = '_EventStartDate'
AND DATE_FORMAT(pm1.meta_value, '%%H:%%i') <> %s", $event_start_time, $event_start_time );
// mysql query to set the end time to the start time plus the duration on every all day event
$fix_end_dates =
"UPDATE $wpdb->postmeta AS pm1
INNER JOIN $wpdb->postmeta pm2
ON (pm1.post_id = pm2.post_id AND pm2.meta_key = '_EventAllDay' AND pm2.meta_value = 'yes')
INNER JOIN $wpdb->postmeta pm3
ON (pm1.post_id = pm3.post_id AND pm3.meta_key = '_EventStartDate')
INNER JOIN $wpdb->postmeta pm4
ON (pm1.post_id = pm4.post_id AND pm4.meta_key = '_EventDuration')
SET pm1.meta_value = DATE_ADD(pm3.meta_value, INTERVAL pm4.meta_value SECOND )
WHERE pm1.meta_key = '_EventEndDate'";
$wpdb->query( $fix_start_dates );
$wpdb->query( $fix_end_dates );
}
/**
* Test PHP and WordPress versions for compatibility
*
* @param string $system - system to be tested such as 'php' or 'wordpress'
*
* @return boolean - is the existing version of the system supported?
*/
public function supportedVersion( $system ) {
if ( $supported = wp_cache_get( $system, 'tribe_version_test' ) ) {
return $supported;
} else {
switch ( strtolower( $system ) ) {
case 'wordpress' :
$supported = version_compare( get_bloginfo( 'version' ), '3.0', '>=' );
break;
case 'php' :
$supported = version_compare( phpversion(), '5.2', '>=' );
break;
}
$supported = apply_filters( 'tribe_events_supported_version', $supported, $system );
wp_cache_set( $system, $supported, 'tribe_version_test' );
return $supported;
}
}
/**
* Display a WordPress or PHP incompatibility error
*/
public function notSupportedError() {
if ( ! self::supportedVersion( 'wordpress' ) ) {
echo '
' . sprintf( esc_html__( 'Sorry, The Events Calendar requires WordPress %s or higher. Please upgrade your WordPress install.', 'the-events-calendar' ), '3.0' ) . '
' . sprintf( esc_html__( 'Sorry, The Events Calendar requires PHP %s or higher. Talk to your Web host about moving you to a newer version of PHP.', 'the-events-calendar' ), '5.2' ) . '
';
}
}
/**
* Display a missing-tribe-common library error
*/
public function missing_common_libs() {
?>
url == $this->getLink() ) {
if ( is_singular( self::POSTTYPE )
|| is_singular( self::VENUE_POST_TYPE )
|| is_tax( self::TAXONOMY )
|| ( ( tribe_is_upcoming()
|| tribe_is_past()
|| tribe_is_month() )
&& isset( $wp_query->query_vars['eventDisplay'] ) )
) {
$item->classes[] = 'current-menu-item current_page_item';
}
break;
}
}
return $items;
}
/**
* Add a checkbox to the menu
*
* @param array $posts
* @param array $args
* @param string $post_type
*
* @return array
*/
public function add_events_checkbox_to_menu( $posts, $args, $post_type ) {
global $_nav_menu_placeholder, $wp_rewrite;
$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval( $_nav_menu_placeholder ) - 1 : - 1;
$archive_slug = $this->getLink();
// In WP 4.4, $post_type is an object rather than an array
if ( is_array( $post_type ) ) {
// support pre WP 4.4
$all_items = $post_type['args']->labels->all_items;
} else {
// support WP 4.4+
$all_items = $post_type->labels->all_items;
}
array_unshift(
$posts, (object) array(
'ID' => 0,
'object_id' => $_nav_menu_placeholder,
'post_content' => '',
'post_excerpt' => '',
'post_title' => $all_items,
'post_type' => 'nav_menu_item',
'type' => 'custom',
'url' => $archive_slug,
)
);
return $posts;
}
/**
* Tribe debug function. usage: Tribe__Debug::debug( 'Message', $data, 'log' );
*
* @param string $title Message to display in log
* @param string|bool $data Optional data to display
* @param string $format Optional format (log|warning|error|notice)
*
*/
public static function debug( $title, $data = false, $format = 'log' ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Debug::debug' );
Tribe__Debug::debug( $title, $data, $format );
}
/**
* Render the debug logging to the php error log. This can be over-ridden by removing the filter.
*
* @param string $title - message to display in log
* @param string|bool $data - optional data to display
* @param string $format - optional format (log|warning|error|notice)
*
*/
public function renderDebug( $title, $data = false, $format = 'log' ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Debug::render' );
Tribe__Debug::render( $title, $data, $format );
}
/**
* Define an admin notice
*
* @param string $key
* @param string $notice
*
* @return bool
*/
public static function setNotice( $key, $notice ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Notices::set_notice' );
return Tribe__Notices::set_notice( $key, $notice );
}
/**
* Check to see if an admin notice exists
*
* @param string $key
*
* @return bool
*/
public static function isNotice( $key ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Notices::is_notice' );
return Tribe__Notices::is_notice( $key );
}
/**
* Remove an admin notice
*
* @param string $key
*
* @return bool
*/
public static function removeNotice( $key ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Notices::remove_notice' );
return Tribe__Notices::remove_notice( $key );
}
/**
* Get the admin notices
*
* @return array
*/
public static function getNotices() {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Notices::get' );
return Tribe__Notices::get();
}
/**
* Get the event taxonomy
*
* @return string
*/
public function get_event_taxonomy() {
return self::TAXONOMY;
}
/**
* Add space to the title in RSS
*
* @param string $title
*
* @return string
*/
public function add_space_to_rss( $title ) {
global $wp_query;
if ( get_query_var( 'eventDisplay' ) == 'upcoming' && get_query_var( 'post_type' ) == self::POSTTYPE ) {
return $title . ' ';
}
return $title;
}
/**
* Update body classes
*
* @param array $classes
*
* @return array
* @TODO move this to template class
*/
public function body_class( $classes ) {
if ( get_query_var( 'post_type' ) == self::POSTTYPE ) {
if ( ! is_admin() && tribe_get_option( 'liveFiltersUpdate', true ) ) {
$classes[] = 'tribe-filter-live';
}
}
return $classes;
}
/**
* Update post classes
*
* @param array $classes
*
* @return array
* @TODO move this to template class
*/
public function post_class( $classes ) {
global $post;
if ( is_object( $post ) && isset( $post->post_type ) && $post->post_type == self::POSTTYPE && $terms = get_the_terms( $post->ID, self::TAXONOMY ) ) {
foreach ( $terms as $term ) {
$classes[] = 'cat_' . sanitize_html_class( $term->slug, $term->term_taxonomy_id );
}
}
return $classes;
}
/**
* Register the post types.
*/
public function registerPostType() {
$this->generatePostTypeLabels();
register_post_type( self::POSTTYPE, apply_filters( 'tribe_events_register_event_type_args', $this->postTypeArgs ) );
// Setup Linked Posts singleton after we've set up the post types that we care about
Tribe__Events__Linked_Posts::instance();
register_taxonomy(
self::TAXONOMY, self::POSTTYPE, array(
'hierarchical' => true,
'update_count_callback' => '',
'rewrite' => array(
'slug' => $this->rewriteSlug . '/' . $this->category_slug,
'with_front' => false,
'hierarchical' => true,
),
'public' => true,
'show_ui' => true,
'labels' => $this->taxonomyLabels,
'capabilities' => array(
'manage_terms' => 'publish_tribe_events',
'edit_terms' => 'publish_tribe_events',
'delete_terms' => 'publish_tribe_events',
'assign_terms' => 'edit_tribe_events',
),
)
);
if ( Tribe__Settings_Manager::get_option( 'showComments', 'no' ) == 'yes' ) {
add_post_type_support( self::POSTTYPE, 'comments' );
}
}
/**
* Get the rewrite slug
*
* @return string
*/
public function getRewriteSlug() {
return sanitize_title( Tribe__Settings_Manager::get_option( 'eventsSlug', 'events' ) );
}
/**
* Get the single post rewrite slug
*
* @return string
*/
public function getRewriteSlugSingular() {
return sanitize_title( Tribe__Settings_Manager::get_option( 'singleEventSlug', 'event' ) );
}
/**
* Get taxonomy rewrite slug.
*
* This method returns a concatenation of the base rewrite slug (ie "events") and the taxonomy slug
* (ie "category"). If you only wish the taxonomy slug itself, you should call the get_tax_slug()
* method.
*
* @deprecated 4.0 please use getRewriteSlug() and get_category_slug() instead
*
* @return string
*/
public function getTaxRewriteSlug() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '4.0', 'Tribe__Events__Main::get_category_slug' );
$slug = $this->getRewriteSlug() . '/' . $this->category_slug;
/**
* @deprecated since 4.0
*/
return apply_filters( 'tribe_events_category_rewrite_slug', $slug );
}
/**
* Returns the string to be used as the taxonomy slug.
*
* @return string
*/
public function get_category_slug() {
/**
* Provides an opportunity to modify the category slug.
*
* @var string
*/
return apply_filters( 'tribe_events_category_slug', sanitize_title( __( 'category', 'the-events-calendar' ) ) );
}
/**
* Get tag rewrite slug.
*
* This method returns a concatenation of the base rewrite slug (ie "events") and the tag taxonomy slug
* (ie "tag"). If you only wish the taxonomy slug itself, you should call the get_tag_slug()
* method.
*
* @deprecated 4.0 please use getRewriteSlug() and get_tag_slug() instead
*
* @return string
*/
public function getTagRewriteSlug() {
_deprecated_function( __CLASS__ . '::' . __METHOD__, '4.0', 'Tribe__Events__Main::get_tag_slug' );
$slug = $this->getRewriteSlug() . '/' . $this->tag_slug;
/**
* @deprecated since 4.0
*/
return apply_filters( 'tribe_events_tag_rewrite_slug', $slug );
}
/**
* Returns the string to be used as the tag slug.
*
* @return string
*/
public function get_tag_slug() {
/**
* Provides an opportunity to modify the tag slug.
*
* @var string
*/
return apply_filters( 'tribe_events_tag_slug', sanitize_title( __( 'tag', 'the-events-calendar' ) ) );
}
/**
* Get venue post type args
*
* @return array
*/
public function getVenuePostTypeArgs() {
return Tribe__Events__Venue::instance()->post_type_args;
}
/**
* Get organizer post type args
*
* @return array
*/
public function getOrganizerPostTypeArgs() {
return Tribe__Events__Organizer::instance()->post_type_args;
}
/**
* Generate custom post type lables
*/
protected function generatePostTypeLabels() {
/**
* Provides an opportunity to modify the labels used for the event post type.
*
* @var array
*/
$this->postTypeArgs['labels'] = apply_filters( 'tribe_events_register_event_post_type_labels', array(
'name' => $this->plural_event_label,
'singular_name' => $this->singular_event_label,
'add_new' => esc_html__( 'Add New', 'the-events-calendar' ),
'add_new_item' => sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_event_label ),
'edit_item' => sprintf( esc_html__( 'Edit %s', 'the-events-calendar' ), $this->singular_event_label ),
'new_item' => sprintf( esc_html__( 'New %s', 'the-events-calendar' ), $this->singular_event_label ),
'view_item' => sprintf( esc_html__( 'View %s', 'the-events-calendar' ), $this->singular_event_label ),
'search_items' => sprintf( esc_html__( 'Search %s', 'the-events-calendar' ), $this->plural_event_label ),
'not_found' => sprintf( esc_html__( 'No %s found', 'the-events-calendar' ), $this->plural_event_label_lowercase ),
'not_found_in_trash' => sprintf( esc_html__( 'No %s found in Trash', 'the-events-calendar' ), $this->plural_event_label_lowercase ),
) );
/**
* Provides an opportunity to modify the labels used for the event category taxonomy.
*
* @var array
*/
$this->taxonomyLabels = apply_filters( 'tribe_events_register_category_taxonomy_labels', array(
'name' => sprintf( esc_html__( '%s Categories', 'the-events-calendar' ), $this->singular_event_label ),
'singular_name' => sprintf( esc_html__( '%s Category', 'the-events-calendar' ), $this->singular_event_label ),
'search_items' => sprintf( esc_html__( 'Search %s Categories', 'the-events-calendar' ), $this->singular_event_label ),
'all_items' => sprintf( esc_html__( 'All %s Categories', 'the-events-calendar' ), $this->singular_event_label ),
'parent_item' => sprintf( esc_html__( 'Parent %s Category', 'the-events-calendar' ), $this->singular_event_label ),
'parent_item_colon' => sprintf( esc_html__( 'Parent %s Category:', 'the-events-calendar' ), $this->singular_event_label ),
'edit_item' => sprintf( esc_html__( 'Edit %s Category', 'the-events-calendar' ), $this->singular_event_label ),
'update_item' => sprintf( esc_html__( 'Update %s Category', 'the-events-calendar' ), $this->singular_event_label ),
'add_new_item' => sprintf( esc_html__( 'Add New %s Category', 'the-events-calendar' ), $this->singular_event_label ),
'new_item_name' => sprintf( esc_html__( 'New %s Category Name', 'the-events-calendar' ), $this->singular_event_label ),
) );
}
/**
* Update custom post type messages
*
* @param $messages
*
* @return mixed
*/
public function updatePostMessage( $messages ) {
global $post, $post_ID;
$messages[ self::POSTTYPE ] = array(
0 => '', // Unused. Messages start at index 1.
1 => sprintf(
esc_html__( '%1$s updated. %2$sView %3$s', 'the-events-calendar' ),
esc_html( $this->singular_event_label ),
'',
esc_html( $this->singular_event_label ) . ''
),
2 => esc_html__( 'Custom field updated.', 'the-events-calendar' ),
3 => esc_html__( 'Custom field deleted.', 'the-events-calendar' ),
4 => sprintf( esc_html__( '%s updated.', 'the-events-calendar' ), $this->singular_event_label ),
/* translators: %s: date and time of the revision */
5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( '%1$s restored to revision from %2$s', 'the-events-calendar' ), $this->singular_event_label, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
6 => sprintf(
esc_html__( 'Event published. %1$sView %2$s', 'the-events-calendar' ),
'',
$this->singular_event_label_lowercase . ''
),
7 => sprintf( esc_html__( '%s saved.', 'the-events-calendar' ), $this->singular_event_label ),
8 => sprintf(
esc_html__( '%1$s submitted. %2$sPreview %3$s', 'the-events-calendar' ),
$this->singular_event_label,
'',
$this->singular_event_label_lowercase . ''
),
9 => sprintf(
esc_html__( '%1$s scheduled for: %2$s. %3$sPreview %4$s', 'the-events-calendar' ),
$this->singular_event_label,
// translators: Publish box date format, see http://php.net/date
'' . date_i18n( esc_html__( 'M j, Y @ G:i', 'the-events-calendar' ),
strtotime( $post->post_date ) ) . '',
'',
$this->singular_event_label_lowercase . ''
),
10 => sprintf(
esc_html__( '%1$s draft updated. %2$sPreview %3$s', 'the-events-calendar' ),
$this->singular_event_label,
'',
$this->singular_event_label_lowercase . ''
),
);
$messages[ self::VENUE_POST_TYPE ] = array(
0 => '', // Unused. Messages start at index 1.
1 => sprintf( esc_html__( '%s updated.', 'the-events-calendar' ), $this->singular_venue_label ),
2 => esc_html__( 'Custom field updated.', 'the-events-calendar' ),
3 => esc_html__( 'Custom field deleted.', 'the-events-calendar' ),
4 => sprintf( esc_html__( '%s updated.', 'the-events-calendar' ), $this->singular_venue_label ),
/* translators: %s: date and time of the revision */
5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( '%1$s restored to revision from %2$s', 'the-events-calendar' ), $this->singular_venue_label, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
6 => sprintf( esc_html__( '%s published.', 'the-events-calendar' ), $this->singular_venue_label ),
7 => sprintf( esc_html__( '%s saved.', 'the-events-calendar' ), $this->singular_venue_label ),
8 => sprintf( esc_html__( '%s submitted.', 'the-events-calendar' ), $this->singular_venue_label ),
9 => sprintf(
esc_html__( '%1$s scheduled for: %2$s.', 'the-events-calendar' ),
$this->singular_venue_label,
// translators: Publish box date format, see http://php.net/date
'' . date_i18n( esc_html__( 'M j, Y @ G:i', 'the-events-calendar' ), strtotime( $post->post_date ) ) . ''
),
10 => sprintf( esc_html__( '%s draft updated.', 'the-events-calendar' ), $this->singular_venue_label ),
);
$messages[ self::ORGANIZER_POST_TYPE ] = array(
0 => '', // Unused. Messages start at index 1.
1 => sprintf( esc_html__( '%s updated.', 'the-events-calendar' ), $this->singular_organizer_label ),
2 => esc_html__( 'Custom field updated.', 'the-events-calendar' ),
3 => esc_html__( 'Custom field deleted.', 'the-events-calendar' ),
4 => sprintf( esc_html__( '%s updated.', 'the-events-calendar' ), $this->singular_organizer_label ),
/* translators: %s: date and time of the revision */
5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( '%s restored to revision from %s', 'the-events-calendar' ), $this->singular_organizer_label, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
6 => sprintf( esc_html__( '%s published.', 'the-events-calendar' ), $this->singular_organizer_label ),
7 => sprintf( esc_html__( '%s saved.', 'the-events-calendar' ), $this->singular_organizer_label ),
8 => sprintf( esc_html__( '%s submitted.', 'the-events-calendar' ), $this->singular_organizer_label ),
9 => sprintf(
esc_html__( '%1$s scheduled for: %2$s.', 'the-events-calendar' ),
$this->singular_organizer_label,
// translators: Publish box date format, see http://php.net/date
'' . date_i18n( esc_html__( 'M j, Y @ G:i', 'the-events-calendar' ), strtotime( $post->post_date ) ) . ''
),
10 => sprintf( esc_html__( '%s draft updated.', 'the-events-calendar' ), $this->singular_organizer_label ),
);
return $messages;
}
/**
* Adds the submenu items for editing the Venues and Organizers.
* Used to be a PRO only feature, but as of 3.0, it is part of Core.
*
*/
public function addVenueAndOrganizerEditor() {
add_submenu_page( 'edit.php?post_type=' . self::POSTTYPE, __( $this->plural_venue_label, 'the-events-calendar' ), __( $this->plural_venue_label, 'the-events-calendar' ), 'edit_tribe_venues', 'edit.php?post_type=' . self::VENUE_POST_TYPE );
add_submenu_page( 'edit.php?post_type=' . self::POSTTYPE, __( $this->plural_organizer_label, 'the-events-calendar' ), __( $this->plural_organizer_label, 'the-events-calendar' ), 'edit_tribe_organizers', 'edit.php?post_type=' . self::ORGANIZER_POST_TYPE );
add_submenu_page( 'edit.php?post_type=' . self::VENUE_POST_TYPE, sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_venue_label ), sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_venue_label ), 'edit_tribe_venues', 'post-new.php?post_type=' . self::VENUE_POST_TYPE );
add_submenu_page( 'edit.php?post_type=' . self::ORGANIZER_POST_TYPE, sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_organizer_label ), sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_organizer_label ), 'edit_tribe_organizers', 'post-new.php?post_type=' . self::ORGANIZER_POST_TYPE );
}
/**
* displays the saved venue dropdown in the event metabox
* Used to be a PRO only feature, but as of 3.0, it is part of Core.
*
* @param int $post_id the event ID for which to create the dropdown
*/
public function displayEventVenueDropdown( $post_id ) {
$venue_id = get_post_meta( $post_id, '_EventVenueID', true );
// Strange but true: the following func lives in core so is safe to call without a func_exists check
$new_community_post = tribe_is_community_edit_event_page() && ! $post_id;
$new_admin_post = 'auto-draft' === get_post_status( $post_id );
if ( ! $venue_id && ( $new_admin_post || $new_community_post ) ) {
$venue_id = $this->defaults()->venue_id();
}
$venue_id = apply_filters( 'tribe_display_event_venue_dropdown_id', $venue_id );
?>
singular_venue_label ); ?>
saved_linked_post_dropdown( Tribe__Events__Venue::POSTTYPE, $venue_id );
$venue_pto = get_post_type_object( self::VENUE_POST_TYPE );
if ( current_user_can( $venue_pto->cap->edit_posts ) ) {
//Use Admin Link Unless on Community Events Editor then use Front End Link to Edit
$edit_link = admin_url( sprintf( 'post.php?action=edit&post=%s', $venue_id ) );
if ( tribe_is_community_edit_event_page() ) {
$edit_link = Tribe__Events__Community__Main::instance()->getUrl( 'edit', $venue_id, null, self::VENUE_POST_TYPE );
}
?>
defaults()->venue_id();
}
$venue_id = apply_filters( 'tribe_display_event_venue_dropdown_id', $venue_id );
// If there is a Venue of some sorts, don't display this message
if ( $venue_id ) {
return;
}
?>
verify_unique_name( $_REQUEST['name'], $_REQUEST['type'] );
die;
}
}
/**
* Allow programmatic override of defaultValueReplace setting
*
* @return boolean
* @deprecated
* @todo remove in 4.5
*/
public function defaultValueReplaceEnabled() {
_deprecated_function( __METHOD__, '4.0', "tribe_get_option( 'defaultValueReplace' )" );
if ( ! is_admin() ) {
return false;
}
return tribe_get_option( 'defaultValueReplace' );
}
/**
* Get the current default value strategy
* @return Tribe__Events__Default_Values
*/
public function defaults() {
return $this->default_values;
}
/**
* Verify that a venue or organizer is unique
*
* @param string $name - name of venue or organizer
* @param string $type - post type
*
* @return boolean
*/
public function verify_unique_name( $name, $post_type ) {
global $wpdb;
$name = stripslashes( $name );
if ( '' == $name ) {
return 1;
}
if ( 'venue' === $post_type ) {
$post_type = Tribe__Events__Venue::POSTTYPE;
} elseif ( 'organizer' === $post_type ) {
$post_type = Tribe__Events__Organizer::POSTTYPE;
}
// TODO update this verification to check all post_status <> 'trash'
$results = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$wpdb->posts} WHERE post_type = %s && post_title = %s && post_status = 'publish'", $post_type, $name ) );
return ( $results ) ? 0 : 1;
}
/**
* Given a date (YYYY-MM-DD), returns the first of the next month
* hat tip to Dan Bernadict for method cleanup
*
* @param string $date
*
* @return string Next month's date
* @throws OverflowException
*/
public function nextMonth( $date ) {
if ( PHP_INT_SIZE <= 4 ) {
if ( date( 'Y-m-d', strtotime( $date ) ) > '2037-11-30' ) {
throw new OverflowException( esc_html__( 'Date out of range.', 'the-events-calendar' ) );
}
}
// Create a new date object: a badly formed date can trigger an exception - in such
// a scenario try again and default to the current time instead
try {
$date = new DateTime( $date );
}
catch ( Exception $e ) {
$date = new DateTime;
}
// set date object to be the first of the month -- all months have this day!
$date->setDate( $date->format( 'Y' ), $date->format( 'm' ), 1 );
// add a month
$date->modify( '+1 month' );
// return the year-month
return $date->format( 'Y-m' );
}
/**
* Given a date (YYYY-MM-DD), return the first of the previous month
* hat tip to Dan Bernadict for method cleanup
*
* @param string $date
*
* @return string Previous month's date
* @throws OverflowException
*/
public function previousMonth( $date ) {
if ( PHP_INT_SIZE <= 4 ) {
if ( date( 'Y-m-d', strtotime( $date ) ) < '1902-02-01' ) {
throw new OverflowException( esc_html__( 'Date out of range.', 'the-events-calendar' ) );
}
}
// Create a new date object: a badly formed date can trigger an exception - in such
// a scenario try again and default to the current time instead
try {
$date = new DateTime( $date );
}
catch ( Exception $e ) {
$date = new DateTime;
}
// set date object to be the first of the month -- all months have this day!
$date->setDate( $date->format( 'Y' ), $date->format( 'm' ), 1 );
// subtract a month
$date->modify( '-1 month' );
// return the year-month
return $date->format( 'Y-m' );
}
/**
* Callback for adding the Meta box to the admin page
*
*/
public function addEventBox() {
add_meta_box(
'tribe_events_event_details', $this->plugin_name, array(
$this,
'EventsChooserBox',
), self::POSTTYPE, 'normal', 'high'
);
add_meta_box(
'tribe_events_event_options', sprintf( esc_html__( '%s Options', 'the-events-calendar' ), $this->singular_event_label ), array(
$this,
'eventMetaBox',
), self::POSTTYPE, 'side', 'default'
);
add_meta_box(
'tribe_events_venue_details', sprintf( esc_html__( '%s Information', 'the-events-calendar' ), $this->singular_venue_label ), array(
$this,
'VenueMetaBox',
), self::VENUE_POST_TYPE, 'normal', 'high'
);
if ( ! class_exists( 'Tribe__Events__Pro__Main' ) ) {
remove_meta_box( 'slugdiv', self::VENUE_POST_TYPE, 'normal' );
}
add_meta_box(
'tribe_events_organizer_details', sprintf( esc_html__( '%s Information', 'the-events-calendar' ), $this->singular_organizer_label ), array(
$this,
'OrganizerMetaBox',
), self::ORGANIZER_POST_TYPE, 'normal', 'high'
);
}
/**
* Include the event editor meta box.
*
*/
public function eventMetaBox() {
include( $this->plugin_path . 'src/admin-views/event-sidebar-options.php' );
}
/**
* Get the date string (shortened).
*
* @param string $date The date.
*
* @return string The pretty (and shortened) date.
*/
public function getDateStringShortened( $date ) {
$monthNames = $this->monthNames();
$dateParts = explode( '-', $date );
$timestamp = mktime( 0, 0, 0, $dateParts[1], 1, $dateParts[0] );
return $monthNames[ date( 'F', $timestamp ) ];
}
/**
* Return the next tab index
*
*/
public function tabIndex() {
$this->tabIndexStart ++;
return $this->tabIndexStart - 1;
}
/**
* Check whether a post is an event.
*
* @param int|WP_Post The event/post id or object.
*
* @return bool Is it an event?
*/
public function isEvent( $event ) {
if ( $event === null || ( ! is_numeric( $event ) && ! is_object( $event ) ) ) {
global $post;
if ( is_object( $post ) && isset( $post->ID ) ) {
$event = $post->ID;
}
}
if ( is_numeric( $event ) ) {
if ( get_post_type( $event ) == self::POSTTYPE ) {
return true;
}
} elseif ( is_object( $event ) ) {
if ( get_post_type( $event ) == self::POSTTYPE ) {
return true;
}
}
return false;
}
/**
* Check whether a post is a venue.
*
* @param int|WP_Post The venue/post id or object.
*
* @return bool Is it a venue?
*/
public function isVenue( $postId = null ) {
if ( $postId === null || ! is_numeric( $postId ) ) {
global $post;
if ( isset( $post->ID ) ) {
$postId = $post->ID;
}
}
if ( isset( $postId ) && get_post_field( 'post_type', $postId ) == self::VENUE_POST_TYPE ) {
return true;
}
return false;
}
/**
* Check whether a post is an organizer.
*
* @param int|WP_Post The organizer/post id or object.
*
* @return bool Is it an organizer?
*/
public function isOrganizer( $postId = null ) {
if ( $postId === null || ! is_numeric( $postId ) ) {
global $post;
$postId = $post->ID;
}
if ( isset( $postId ) && get_post_field( 'post_type', $postId ) == self::ORGANIZER_POST_TYPE ) {
return true;
}
return false;
}
/**
* Modify the WHERE clause of query when fetching next/prev posts so events with identical times are not excluded
*
* This method ensures that when viewing single events that occur at a given time, other events
* that occur at the exact same time are are not excluded from the prev/next links
*
* @since 4.0.2
*
* @param string $where_sql WHERE SQL statement
* @param WP_Query $query WP_Query object
*
* return string
*/
public function get_closest_event_where( $where_sql ) {
// if we are in this method, we KNOW there is a section of the SQL that looks like this:
// ( table.meta_key = '_EventStartDate' AND CAST( table.meta_value AS DATETIME ) [<|>] '2015-01-01 00:00:00' )
// What we want to do is to extract all the portions of the WHERE BEFORE that section, all the
// portions AFTER that section, and then rebuild that section to be flexible enough to include
// events that have the SAME datetime as the event we're comparing against. Sadly, this requires
// some regex-fu.
//
// The end-game is to change the known SQL line (from above) into the following:
//
// (
// ( table.meta_key = '_EventStartDate' AND CAST( table.meta_value AS DATETIME ) [<|>] '2015-01-01 00:00:00' )
// OR (
// ( table.meta_key = '_EventStartDate' AND CAST( table.meta_value AS DATETIME ) = '2015-01-01 00:00:00' )
// AND
// table.post_id [<|>] POST_ID
// )
// )
//
// Here's the regex portion that matches the part that we know. From that line, we want to
// have a few capture groups.
// 1) We need the whole thing
// 2) We need the meta table alias
// 3) We need the < or > sign
// Here's the regex for getting the meta table alias
$meta_table_regex = '([^\.]+)\.meta_key\s*=\s*';
// Here's the regex for the middle section of the know line
$middle_regex = '[\'"]_EventStartDate[\'"]\s+AND\s+CAST[^\)]+AS DATETIME\s*\)\s*';
// Here's the regex for the < and > sign
$gt_lt_regex = '(\<|\>)';
// Let's put that line together, making sure we are including the wrapping parens and the
// characters that make up the rest of the line - spacing in front, non paren characters at
// the end
$known_sql_regex = "\(\s*{$meta_table_regex}{$middle_regex}{$gt_lt_regex}[^\)]+\)";
// The known SQL line will undoubtedly be included amongst other WHERE statements. We need
// to generically grab the SQL before and after the known line so we can rebuild our nice new
// where statement. Here's the regex that brings it all together.
// Note: We are using the 'm' modifier so that the regex looks over multiple lines as well
// as the 's' modifier so that '.' includes linebreaks
$full_regex = "/(.*)($known_sql_regex)(.*)/ms";
// here's a regex to grab the post ID from a portion of the WHERE statement
$post_id_regex = '/NOT IN\s*\(([0-9]+)\)/';
if ( preg_match( $full_regex, $where_sql, $matches ) ) {
// place capture groups into vars that are easier to read
$before = $matches[1];
$known = $matches[2];
$alias = $matches[3];
$gt_lt = $matches[4];
$after = $matches[5];
// copy the known line but replace the < or > symbol with an =
$equal = preg_replace( '/(\<|\>)/', '=', $known );
// extract the post ID from the extra "before" or "after" WHERE
if (
preg_match( $post_id_regex, $before, $post_id )
|| preg_match( $post_id_regex, $after, $post_id )
) {
$post_id = absint( $post_id[1] );
} else {
// if we can't find the post ID, then let's bail
return $where_sql;
}
// rebuild the WHERE clause
$where_sql = "{$before} (
{$known}
OR (
{$equal}
AND {$alias}.post_id {$gt_lt} {$post_id}
)
) {$after} ";
}
return $where_sql;
}
/**
* Get the prev/next post for a given event. Ordered by start date instead of ID.
*
* @param WP_Post $post The post/event.
* @param string $mode Either 'next' or 'previous'.
*
* @return null|WP_Post
*/
public function get_closest_event( $post, $mode = 'next' ) {
global $wpdb;
if ( 'previous' === $mode ) {
$order = 'DESC';
$direction = '<';
} else {
$order = 'ASC';
$direction = '>';
$mode = 'next';
}
$args = array(
'post__not_in' => array( $post->ID ),
'order' => $order,
'orderby' => "TIMESTAMP( $wpdb->postmeta.meta_value ) ID",
'posts_per_page' => 1,
'meta_query' => array(
array(
'key' => '_EventStartDate',
'value' => $post->EventStartDate,
'type' => 'DATETIME',
'compare' => $direction,
),
array(
'key' => '_EventHideFromUpcoming',
'compare' => 'NOT EXISTS',
),
'relation' => 'AND',
),
);
/**
* Allows the query arguments used when retrieving the next/previous event link
* to be modified.
*
* @var array $args
* @var WP_Post $post
*/
$args = (array) apply_filters( "tribe_events_get_{$mode}_event_link", $args, $post );
add_filter( 'posts_where', array( $this, 'get_closest_event_where' ) );
$results = tribe_get_events( $args );
remove_filter( 'posts_where', array( $this, 'get_closest_event_where' ) );
$event = null;
// If we successfully located the next/prev event, we should have precisely one element in $results
if ( 1 === count( $results ) ) {
$event = current( $results );
}
/**
* Affords an opportunity to modify the event used to generate the event link (typically for
* the next or previous event in relation to $post).
*
* @var WP_Post $post
* @var string $mode (typically "previous" or "next")
*/
return apply_filters( 'tribe_events_get_closest_event', $event, $post, $mode );
}
/**
* Get a "previous/next post" link for events. Ordered by start date instead of ID.
*
* @param WP_Post $post The post/event.
* @param string $mode Either 'next' or 'previous'.
* @param mixed $anchor
*
* @return string The link (with tags).
*/
public function get_event_link( $post, $mode = 'next', $anchor = false ) {
$link = null;
$event = $this->get_closest_event( $post, $mode );
// If we successfully located the next/prev event, we should have precisely one element in $results
if ( $event ) {
if ( ! $anchor ) {
$anchor = apply_filters( 'the_title', $event->post_title, $event->ID );
} elseif ( strpos( $anchor, '%title%' ) !== false ) {
// get the nicely filtered post title
$title = apply_filters( 'the_title', $event->post_title, $event->ID );
// escape special characters used in the second parameter of preg_replace
$title = str_replace(
array(
'\\',
'$',
),
array(
'\\\\',
'\$',
),
$title
);
$anchor = preg_replace( '|%title%|', $title, $anchor );
}
$link = '' . $anchor . '';
}
/**
* Affords an opportunity to modify the event link (typically for the next or previous
* event in relation to $post).
*
* @var string $link
* @var WP_Post $post
* @var string $mode (typically "previous" or "next")
* @var string $anchor
*/
return apply_filters( 'tribe_events_get_event_link', $link, $post, $mode, $anchor );
}
/**
* Add meta links to the Plugins list page.
*
* @param array $links The current action links.
* @param string $file The plugin to see if we are on TEC.
*
* @return array The modified action links array.
*/
public function addMetaLinks( $links, $file ) {
if ( $file == $this->plugin_dir . 'the-events-calendar.php' ) {
$anchor = esc_html__( 'Support', 'the-events-calendar' );
$links[] = '' . $anchor . '';
$anchor = esc_html__( 'View All Add-Ons', 'the-events-calendar' );
$link = add_query_arg(
array(
'utm_campaign' => 'in-app',
'utm_medium' => 'plugin-tec',
'utm_source' => 'plugins-manager',
), self::$tribeUrl . self::$addOnPath
);
$links[] = '' . $anchor . '';
}
return $links;
}
/**
* Register the dashboard widget.
*
*/
public function dashboardWidget() {
wp_add_dashboard_widget(
'tribe_dashboard_widget', esc_html__( 'News from Modern Tribe', 'the-events-calendar' ), array(
$this,
'outputDashboardWidget',
)
);
}
/**
* Echo the dashboard widget.
*
* @param int $items
*
*/
public function outputDashboardWidget( $items = 10 ) {
echo '
';
}
/**
* Set the class property postExceptionThrown.
*/
public function setPostExceptionThrown( $thrown ) {
$this->postExceptionThrown = $thrown;
}
/**
* Get the thrown post exception.
*
* @return mixed
*/
public function getPostExceptionThrown() {
return $this->postExceptionThrown;
}
/**
* Echoes upsell stuff, if it should.
*
* @param int $postId
*
*/
public function maybeShowMetaUpsell( $postId ) {
?>
is_enabled() ) {
return;
}
global $wp_admin_bar;
$admin_bar->init( $wp_admin_bar );
}
/**
* Displays the View Calendar link at the top of the Events list in admin.
*
*/
public function addViewCalendar() {
if ( Tribe__Admin__Helpers::instance()->is_screen( 'edit-' . self::POSTTYPE ) ) {
//Output hidden DIV with Calendar link to be displayed via javascript
echo '
';
}
}
/**
* Set the menu-edit-page to default display the events-related items.
*
*/
public function setInitialMenuMetaBoxes() {
global $current_screen;
if ( empty( $current_screen->id ) || 'nav-menus' !== $current_screen->id ) {
return;
}
$user_id = wp_get_current_user()->ID;
if ( get_user_option( 'tribe_setDefaultNavMenuBoxes', $user_id ) ) {
return;
}
$current_hidden_boxes = array();
$current_hidden_boxes = get_user_option( 'metaboxhidden_nav-menus', $user_id );
if ( $array_key = array_search( 'add-' . self::POSTTYPE, $current_hidden_boxes ) ) {
unset( $current_hidden_boxes[ $array_key ] );
}
if ( $array_key = array_search( 'add-' . self::VENUE_POST_TYPE, $current_hidden_boxes ) ) {
unset( $current_hidden_boxes[ $array_key ] );
}
if ( $array_key = array_search( 'add-' . self::ORGANIZER_POST_TYPE, $current_hidden_boxes ) ) {
unset( $current_hidden_boxes[ $array_key ] );
}
if ( $array_key = array_search( 'add-' . self::TAXONOMY, $current_hidden_boxes ) ) {
unset( $current_hidden_boxes[ $array_key ] );
}
update_user_option( $user_id, 'metaboxhidden_nav-menus', $current_hidden_boxes, true );
update_user_option( $user_id, 'tribe_setDefaultNavMenuBoxes', true, true );
}
/**
* Add links to the plugins row
*
* @param $actions
*
* @return mixed
* @todo move to an admin class
*/
public function addLinksToPluginActions( $actions ) {
$actions['settings'] = '' . esc_html__( 'Settings', 'the-events-calendar' ) . '';
$actions['tribe-calendar'] = '' . esc_html__( 'Calendar', 'the-events-calendar' ) . '';
return $actions;
}
/**
* Add help menu item to the admin (unless blocked via network admin settings).
*/
public function addHelpAdminMenuItem() {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::add_help_admin_menu_item' );
Tribe__Settings_Manager::instance()->add_help_admin_menu_item();
}
/**
* When the edit-tags.php screen loads, setup filters
* to fix the tagcloud links
*
* @deprecated 4.1.2
*/
public function prepare_to_fix_tagcloud_links() {
_deprecated_function( __METHOD__, '4.1.2' );
if ( Tribe__Admin__Helpers::instance()->is_post_type_screen( self::POSTTYPE ) ) {
add_filter( 'get_edit_term_link', array( $this, 'add_post_type_to_edit_term_link' ), 10, 4 );
}
}
/**
* Tag clouds in the admin don't pass the post type arg
* when getting the edit link. If we're on the tag admin
* in Events post type context, make sure we add that
* arg to the edit tag link
*
* @deprecated 4.1.2
*
* @param string $link
* @param int $term_id
* @param string $taxonomy
* @param string $context
*
* @return string
*/
public function add_post_type_to_edit_term_link( $link, $term_id, $taxonomy, $context ) {
_deprecated_function( __METHOD__, '4.1.2' );
if ( $taxonomy == 'post_tag' && empty( $context ) ) {
$link = add_query_arg( array( 'post_type' => self::POSTTYPE ), $link );
}
return esc_url_raw( $link );
}
/**
* Set up the list view in the view selector in the tribe events bar.
*
* @param array $views The current views array.
*
* @return array The modified views array.
*/
public function setup_listview_in_bar( $views ) {
$views[] = array(
'displaying' => 'list',
'event_bar_hook' => 'tribe_events_before_template',
'anchor' => esc_html__( 'List', 'the-events-calendar' ),
'url' => tribe_get_listview_link(),
);
return $views;
}
/**
* Set up the calendar view in the view selector in the tribe events bar.
*
* @param array $views The current views array.
*
* @return array The modified views array.
*/
public function setup_gridview_in_bar( $views ) {
$views[] = array(
'displaying' => 'month',
'event_bar_hook' => 'tribe_events_month_before_template',
'anchor' => esc_html__( 'Month', 'the-events-calendar' ),
'url' => tribe_get_gridview_link(),
);
return $views;
}
/**
* Add day view to the views selector in the tribe events bar.
*
* @param array $views The current array of views registered to the tribe bar.
*
* @return array The views registered with day view added.
*/
public function setup_dayview_in_bar( $views ) {
$views[] = array(
'displaying' => 'day',
'anchor' => esc_html__( 'Day', 'the-events-calendar' ),
'event_bar_hook' => 'tribe_events_before_template',
'url' => tribe_get_day_link(),
);
return $views;
}
/**
* Set up the keyword search in the tribe events bar.
*
* @param array $filters The current filters in the bar array.
*
* @return array The modified filters array.
*/
public function setup_keyword_search_in_bar( $filters ) {
$value = '';
if ( ! empty( $_REQUEST['tribe-bar-search'] ) ) {
$value = esc_attr( $_REQUEST['tribe-bar-search'] );
}
if ( tribe_get_option( 'tribeDisableTribeBar', false ) == false ) {
$filters['tribe-bar-search'] = array(
'name' => 'tribe-bar-search',
'caption' => esc_html__( 'Search', 'the-events-calendar' ),
'html' => '',
);
}
return $filters;
}
/**
* Set up the date search in the tribe events bar.
*
* @param array $filters The current filters in the bar array.
*
* @return array The modified filters array.
*/
public function setup_date_search_in_bar( $filters ) {
global $wp_query;
$value = apply_filters( 'tribe-events-bar-date-search-default-value', '' );
if ( ! empty( $_REQUEST['tribe-bar-date'] ) ) {
$value = $_REQUEST['tribe-bar-date'];
}
$caption = esc_html__( 'Date', 'the-events-calendar' );
if ( tribe_is_month() ) {
$caption = sprintf( esc_html__( '%s In', 'the-events-calendar' ), $this->plural_event_label );
} elseif ( tribe_is_list_view() ) {
$caption = sprintf( esc_html__( '%s From', 'the-events-calendar' ), $this->plural_event_label );
} elseif ( tribe_is_day() ) {
$caption = esc_html__( 'Day Of', 'the-events-calendar' );
$value = date( Tribe__Date_Utils::DBDATEFORMAT, strtotime( $wp_query->query_vars['eventDate'] ) );
}
$caption = apply_filters( 'tribe_bar_datepicker_caption', $caption );
$filters['tribe-bar-date'] = array(
'name' => 'tribe-bar-date',
'caption' => $caption,
'html' => '',
);
return $filters;
}
/**
* Removes views that have been deselected in the Template Settings as hidden from the view array.
*
*
* @param array $views The current views array.
* @param bool $visible
*
* @return array The new views array.
*/
public function remove_hidden_views( $views, $visible = true ) {
$enable_views_defaults = array();
foreach ( $views as $view ) {
$enable_views_defaults[] = $view['displaying'];
}
if ( $visible ) {
$enable_views = tribe_get_option( 'tribeEnableViews', $enable_views_defaults );
foreach ( $views as $index => $view ) {
if ( ! in_array( $view['displaying'], $enable_views ) ) {
unset( $views[ $index ] );
}
}
}
return $views;
}
/**
* Disable the canonical redirect if tribe_paged is set
*
* @param WP_Query $query The current query object.
*
* @return WP_Query The modified query object.
*/
public function set_tribe_paged( $query ) {
if ( ! empty( $_REQUEST['tribe_paged'] ) ) {
add_filter( 'redirect_canonical', '__return_false' );
}
return $query;
}
/**
* Add filters to register custom cron schedules
*
*/
public function filter_cron_schedules() {
add_filter( 'cron_schedules', array( $this, 'register_30min_interval' ) );
}
/**
* Add a new scheduled task interval (of 30mins).
*
* @param array $schedules
* @return array
*/
public function register_30min_interval( $schedules ) {
$schedules['every_30mins'] = array(
'interval' => 30 * MINUTE_IN_SECONDS,
'display' => esc_html__( 'Once Every 30 Mins', 'tribe-events-pro' ),
);
return $schedules;
}
/**
* Facilitates the import of events in WXR format (ie, via the core WP importer).
*
* When WP imports posts it avoids duplication by comparing the post name, date and
* type of each. Once a post has been imported, if another post matching the above
* criteria is found it is discarded.
*
* In the case of recurring events this would cause all but the first in a series
* to be discarded and so we workaround the problem by altering the title (and
* restoring it afterwards - during "wp_import_post_data_processed").
*
* We apply this to *all* events being imported because we also need to cater for
* a scenario where events that were originally created as part of a set of
* recurring events may later have been broken out of the chain into standalone
* events (otherwise we could restrict this operation to only those events with
* a post parent).
*
* We're retaining this logic in core (rather than move it to PRO) since it's
* posible for data from a site running PRO to be imported into a site running only
* core.
*
* @see Tribe__Events__Main::filter_wp_import_data_after()
*
* @param array $post
*
* @return array
*/
public function filter_wp_import_data_before( $post ) {
if ( $post['post_type'] === self::POSTTYPE ) {
$start_date = '';
if ( isset( $post['postmeta'] ) && is_array( $post['postmeta'] ) ) {
foreach ( $post['postmeta'] as $meta ) {
if ( $meta['key'] == '_EventStartDate' ) {
$start_date = $meta['value'];
break;
}
}
}
if ( ! empty( $start_date ) ) {
$post['post_title'] .= '[tribe_start_date]' . $start_date . '[/tribe_start_date]';
}
}
return $post;
}
/**
* Event titles have been modified by filter_wp_import_data_before().
* This puts them back how they belong.
*
* @param array $post
*
* @return array
* @see Tribe__Events__Main::filter_wp_import_data_before()
*/
public function filter_wp_import_data_after( $post ) {
if ( $post['post_type'] == self::POSTTYPE ) {
$post['post_title'] = preg_replace( '#\[tribe_start_date\].*?\[\/tribe_start_date\]#', '', $post['post_title'] );
}
return $post;
}
/**
* Insert an array after a specified key within another array.
*
* @param $key
* @param $source_array
* @param $insert_array
*
* @return array
*
*/
public static function array_insert_after_key( $key, $source_array, $insert_array ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Main::array_insert_after_key' );
return self::instance()->common()->array_insert_after_key( $key, $source_array, $insert_array );
}
/**
* Insert an array immediately before a specified key within another array.
*
* @param $key
* @param $source_array
* @param $insert_array
*
* @return array
*/
public static function array_insert_before_key( $key, $source_array, $insert_array ) {
_deprecated_function( __METHOD__, '4.0', 'Tribe__Main::array_insert_before_key' );
return self::instance()->common()->array_insert_before_key( $key, $source_array, $insert_array );
}
public function run_updates() {
if ( $this->updater()->update_required() ) {
$this->updater()->do_updates();
}
}
/**
* Helper used to test if PRO is present and activated.
*
* This method should no longer be used, but is being retained to avoid potential
* for fatal errors where core is updated before an addon plugin - such as Community
* Events 3.4 or earlier - which might otherwise occur were it removed completely.
*
* @deprecated as of 3.7, remove in 4.0
*
* @param string $version
*
* @return bool
*/
public static function ecpActive( $version = '2.0.7' ) {
return class_exists( 'Tribe__Events__Pro__Main' ) && defined( 'Tribe__Events__Pro__Main::VERSION' ) && version_compare( Tribe__Events__Pro__Main::VERSION, $version, '>=' );
}
protected function init_autoloading() {
$prefixes = array(
'Tribe__Events__' => $this->plugin_path . 'src/Tribe',
'ForceUTF8__' => $this->plugin_path . 'vendor/ForceUTF8',
);
if ( ! class_exists( 'Tribe__Autoloader' ) ) {
require_once $GLOBALS['tribe-common-info']['dir'] . '/Autoloader.php';
$prefixes['Tribe__'] = $GLOBALS['tribe-common-info']['dir'];
}
$autoloader = Tribe__Autoloader::instance();
$autoloader->register_prefixes( $prefixes );
// deprecated classes are registered in a class to path fashion
foreach ( glob( $this->plugin_path . 'src/deprecated/*.php' ) as $file ) {
$class_name = str_replace( '.php', '', basename( $file ) );
$autoloader->register_class( $class_name, $file );
}
$autoloader->register_autoloader();
}
/**
* Registers the list widget
*/
public function register_list_widget() {
register_widget( 'Tribe__Events__List_Widget' );
}
/**
* Sets the globally shared `$_tribe_meta_factory` object
*
* @deprecated 4.3
*/
public function set_meta_factory_global() {
_deprecated_function( __METHOD__, '4.3' );
global $_tribe_meta_factory;
$_tribe_meta_factory = new Tribe__Events__Meta_Factory();
}
/**
* Checks if the standalone Tickets plugin is activated.
* If it's not, it loads the Tickets framework from our
* vendor/ submodule.
*/
public function maybe_load_tickets_framework() {
if ( defined( 'EVENT_TICKETS_DIR' ) ) {
return;
}
// Give the standalone plugin a chance to load on activation
// WordPress loads all the active plugins before activating a new one.
if ( isset( $_GET['action'] ) && $_GET['action'] == 'activate' && isset( $_GET['plugin'] ) && strstr( $_GET['plugin'], 'event-tickets.php' ) ) {
return;
}
// if there aren't any ticket plugins activated, bail
if (
! defined( 'EVENT_TICKETS_PLUS' )
&& ! defined( 'EVENTS_TICKETS_EDD_DIR' )
&& ! defined( 'EVENTS_TICKETS_SHOPP_DIR' )
&& ! defined( 'EVENTS_TICKETS_WOO_DIR' )
&& ! defined( 'EVENTS_TICKETS_WPEC_DIR' )
) {
return;
}
require_once $this->plugin_path . 'vendor/tickets/event-tickets.php';
Tribe__Tickets__Main::instance()->plugins_loaded();
}
/**
* Inject TEC specific setting fields into the general tab
*
* @param array $general_tab_fields Fields for the general settings tab
*
* @return array
*/
public function general_settings_tab_fields( $general_tab_fields ) {
require_once $this->plugin_path . 'src/admin-views/tribe-options-general.php';
return $general_tab_fields;
}
/**
* Inject TEC specific setting fields into the display tab
*
* @param array $display_tab_fields Fields for the display settings tab
*
* @return array
*/
public function display_settings_tab_fields( $display_tab_fields ) {
require_once $this->plugin_path . 'src/admin-views/tribe-options-display.php';
return $display_tab_fields;
}
/**
* When TEC is activated, the Events top level menu item in the dashboard needs the post_type appended to it
*
* @param string $url Settings URL to filter
*
* @return string
*/
public function tribe_settings_url( $url ) {
return add_query_arg( array( 'post_type' => self::POSTTYPE ), $url );
}
/**
* Adds post types to the post_types array used to determine if on a post type screen
*
* @param array $post_types Collection of post types
*
* @return array
*/
public function is_post_type_screen_post_types( $post_types ) {
foreach ( self::getPostTypes() as $post_type ) {
$post_types[] = $post_type;
}
return $post_types;
}
/**
* If tickets don't have an end date, let's provide the end date from the event
*/
public function default_end_date_for_tickets( $date, $post_id ) {
$post = get_post( $post_id );
if ( self::POSTTYPE !== $post->post_type ) {
return $date;
}
return tribe_get_end_date( $post_id, false, 'Y-m-d G:i' );
}
/**
* Set the currency symbol from tribe_events meta data if available
*
* @param boolean $currency_symbol Currency symbol to use
* @param int $post_id Post ID
*
* @return string
*/
public function maybe_set_currency_symbol_with_post( $currency_symbol, $post_id ) {
// if the currency symbol is already set, don't alter it
if ( null !== $currency_symbol ) {
return $currency_symbol;
}
// if there isn't a post id, don't change the symbol
if ( ! $post_id ) {
return $currency_symbol;
}
// if the post isn't a tribe_events post type, don't alter the symbol
$post = get_post( $post_id );
if ( self::POSTTYPE !== $post->post_type ) {
return $currency_symbol;
}
$currency_symbol = tribe_get_event_meta( $post_id, '_EventCurrencySymbol', true );
return $currency_symbol;
}
/**
* Set the currency position from tribe_events meta data if available
*
* @param boolean $reverse_position Whether to reverse the location of the currency symbol
* @param int $post_id Post ID
*
* @return boolean
*/
public function maybe_set_currency_position_with_post( $reverse_position, $post_id ) {
// if the currency symbol is already set, don't alter it
if ( null !== $reverse_position ) {
return $reverse_position;
}
// if there isn't a post id, don't change the symbol
if ( ! $post_id ) {
return $reverse_position;
}
// if the post isn't a tribe_events post type, don't alter the symbol
$post = get_post( $post_id );
if ( self::POSTTYPE !== $post->post_type ) {
return $reverse_position;
}
$reverse_position = tribe_get_event_meta( $post_id, '_EventCurrencyPosition', true );
$reverse_position = ( 'suffix' === $reverse_position );
return $reverse_position;
}
} // end Tribe__Events__Main class
} // end if !class_exists Tribe__Events__Main