true, 'after' => true ); /** * Args for the event post type * @var array */ protected $postTypeArgs = array( 'public' => true, 'rewrite' => array( 'slug' => 'event', 'with_front' => false ), 'menu_position' => 6, 'supports' => array( 'title', 'editor', 'excerpt', 'author', 'thumbnail', 'custom-fields', 'comments', ), 'taxonomies' => array( 'post_tag' ), 'capability_type' => array( 'tribe_event', 'tribe_events' ), 'map_meta_cap' => true, 'has_archive' => true, ); /** * Args for venue post type * @var array */ public $postVenueTypeArgs = array( 'public' => false, 'rewrite' => array( 'slug' => 'venue', 'with_front' => false ), 'show_ui' => true, 'show_in_menu' => 0, 'supports' => array( 'title', 'editor' ), 'capability_type' => array( 'tribe_venue', 'tribe_venues' ), 'map_meta_cap' => true, 'exclude_from_search' => true, ); protected $taxonomyLabels; /** * Args for organizer post type * @var array */ public $postOrganizerTypeArgs = array( 'public' => false, 'rewrite' => array( 'slug' => 'organizer', 'with_front' => false ), 'show_ui' => true, 'show_in_menu' => 0, 'supports' => array( 'title', 'editor' ), 'capability_type' => array( 'tribe_organizer', 'tribe_organizers' ), 'map_meta_cap' => true, 'exclude_from_search' => true, ); public static $tribeUrl = 'http://tri.be/'; public static $tecUrl = 'http://theeventscalendar.com/'; public static $addOnPath = 'products/'; public static $dotOrgSupportUrl = 'http://wordpress.org/tags/the-events-calendar'; protected static $instance; public $rewriteSlug = 'events'; public $rewriteSlugSingular = 'event'; public $category_slug = 'category'; public $tag_slug = 'tag'; public $monthSlug = 'month'; /** @deprecated 4.0 */ public $taxRewriteSlug = 'event/category'; /** @deprecated 4.0 */ public $tagRewriteSlug = 'event/tag'; /** @var Tribe__Events__Admin__Timezone_Settings */ public $timezone_settings; // @todo remove in 4.0 public $upcomingSlug = 'upcoming'; public $pastSlug = 'past'; public $listSlug = 'list'; public $daySlug = 'day'; public $todaySlug = 'today'; protected $postExceptionThrown = false; /** * Deprecated property in 4.0. Use plugin_dir instead */ public $pluginDir; /** * Deprecated property in 4.0. Use plugin_path instead */ public $pluginPath; /** * Deprecated property in 4.0. Use plugin_url instead */ public $pluginUrl; /** * Deprecated property in 4.0. Use plugin_name instead */ public $pluginName; public $displaying; public $plugin_dir; public $plugin_path; public $plugin_url; public $plugin_name; public $date; protected $tabIndexStart = 2000; public $metaTags = array( '_EventAllDay', '_EventStartDate', '_EventEndDate', '_EventStartDateUTC', '_EventEndDateUTC', '_EventDuration', '_EventVenueID', '_EventShowMapLink', '_EventShowMap', '_EventCurrencySymbol', '_EventCurrencyPosition', '_EventCost', '_EventCostMin', '_EventCostMax', '_EventURL', '_EventOrganizerID', '_EventPhone', '_EventHideFromUpcoming', '_EventTimezone', '_EventTimezoneAbbr', self::EVENTSERROROPT, ); public $venueTags = array( '_VenueVenue', '_VenueCountry', '_VenueAddress', '_VenueCity', '_VenueStateProvince', '_VenueState', '_VenueProvince', '_VenueZip', '_VenuePhone', '_VenueURL', ); public $organizerTags = array( '_OrganizerOrganizer', '_OrganizerEmail', '_OrganizerWebsite', '_OrganizerPhone', ); public $currentPostTimestamp; public $daysOfWeekShort; public $daysOfWeek; public $daysOfWeekMin; public $monthsFull; public $monthsShort; public $singular_venue_label; public $plural_venue_label; public $singular_organizer_label; public $plural_organizer_label; public $singular_event_label; public $plural_event_label; /** @var Tribe__Events__Default_Values */ private $default_values = null; public static $tribeEventsMuDefaults; /** * Static Singleton Factory Method * * @return Tribe__Events__Main */ public static function instance() { if ( ! isset( self::$instance ) ) { $className = __CLASS__; self::$instance = new $className; } return self::$instance; } /** * Initializes plugin variables and sets up WordPress hooks/actions. */ protected function __construct() { $this->pluginPath = $this->plugin_path = trailingslashit( dirname( dirname( dirname( __FILE__ ) ) ) ); $this->pluginDir = $this->plugin_dir = trailingslashit( basename( $this->plugin_path ) ); $this->pluginUrl = $this->plugin_url = plugins_url( $this->plugin_dir ); $this->maybe_set_common_lib_info(); // let's initialize tec silly-early to avoid fatals with upgrades from 3.x to 4.x add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 0 ); } public function plugins_loaded() { // include the autoloader class $this->init_autoloading(); add_action( 'init', array( $this, 'loadTextDomain' ), 1 ); if ( self::supportedVersion( 'wordpress' ) && self::supportedVersion( 'php' ) ) { $this->addHooks(); $this->maybe_load_tickets_framework(); $this->loadLibraries(); } else { // Either PHP or WordPress version is inadequate so we simply return an error. add_action( 'admin_head', array( $this, 'notSupportedError' ) ); } } public function maybe_set_common_lib_info() { $common_version = file_get_contents( $this->plugin_path . 'common/src/Tribe/Main.php' ); // if there isn't a tribe-common version, bail if ( ! preg_match( "/const\s+VERSION\s*=\s*'([^']+)'/m", $common_version, $matches ) ) { add_action( 'admin_head', array( $this, 'missing_common_libs' ) ); return; } $common_version = $matches[1]; if ( empty( $GLOBALS['tribe-common-info'] ) ) { $GLOBALS['tribe-common-info'] = array( 'dir' => "{$this->plugin_path}common/src/Tribe", 'version' => $common_version, ); } elseif ( 1 == version_compare( $GLOBALS['tribe-common-info']['version'], $common_version, '<' ) ) { $GLOBALS['tribe-common-info'] = array( 'dir' => "{$this->plugin_path}common/src/Tribe", 'version' => $common_version, ); } } /** * Load all the required library files. */ protected function loadLibraries() { // initialize the common libraries $this->common(); // Tribe common resources require_once $this->plugin_path . 'vendor/tribe-common-libraries/tribe-common-libraries.class.php'; // Load CSV importer require_once $this->plugin_path . 'src/io/csv/ecp-events-importer.php'; // Load Template Tags require_once $this->plugin_path . 'src/functions/template-tags/query.php'; require_once $this->plugin_path . 'src/functions/template-tags/general.php'; require_once $this->plugin_path . 'src/functions/template-tags/month.php'; require_once $this->plugin_path . 'src/functions/template-tags/loop.php'; require_once $this->plugin_path . 'src/functions/template-tags/google-map.php'; require_once $this->plugin_path . 'src/functions/template-tags/organizer.php'; require_once $this->plugin_path . 'src/functions/template-tags/venue.php'; require_once $this->plugin_path . 'src/functions/template-tags/date.php'; require_once $this->plugin_path . 'src/functions/template-tags/link.php'; require_once $this->plugin_path . 'src/functions/template-tags/widgets.php'; require_once $this->plugin_path . 'src/functions/template-tags/meta.php'; // Load Advanced Functions require_once $this->plugin_path . 'src/functions/advanced-functions/event.php'; require_once $this->plugin_path . 'src/functions/advanced-functions/venue.php'; require_once $this->plugin_path . 'src/functions/advanced-functions/organizer.php'; // Load Deprecated Template Tags if ( ! defined( 'TRIBE_DISABLE_DEPRECATED_TAGS' ) ) { require_once $this->plugin_path . 'src/functions/template-tags/deprecated.php'; } } /** * Common library object accessor method */ public function common() { static $common; if ( ! $common ) { $common = new Tribe__Main( $this ); } return $common; } /** * Updater object accessor method */ public function updater() { static $updater; if ( ! $updater ) { $updater = new Tribe__Events__Updater( self::VERSION ); } return $updater; } /** * before_html_data_wrapper adds a persistant tag to wrap the event display with a * way for jQuery to maintain state in the dom. Also has a hook for filtering data * attributes for inclusion in the dom * * @param string $html * * @return string */ public function before_html_data_wrapper( $html ) { global $wp_query; if ( ! $this->show_data_wrapper['before'] ) { return $html; } $tec = self::instance(); $data_attributes = array( 'live_ajax' => tribe_get_option( 'liveFiltersUpdate', true ) ? 1 : 0, 'datepicker_format' => tribe_get_option( 'datepickerFormat' ), 'category' => is_tax( $tec->get_event_taxonomy() ) ? get_query_var( 'term' ) : '', ); // allow data attributes to be filtered before display $data_attributes = (array) apply_filters( 'tribe_events_view_data_attributes', $data_attributes ); // loop through the attributes and build the html output foreach ( $data_attributes as $id => $attr ) { $attribute_html[] = sprintf( 'data-%s="%s"', sanitize_title( $id ), esc_attr( $attr ) ); } $this->show_data_wrapper['before'] = false; // return filtered html return apply_filters( 'tribe_events_view_before_html_data_wrapper', sprintf( '
%s', implode( ' ', $attribute_html ), $html ), $data_attributes, $html ); } /** * after_html_data_wrapper close out the persistant dom wrapper * * @param string $html * * @return string */ public function after_html_data_wrapper( $html ) { if ( ! $this->show_data_wrapper['after'] ) { return $html; } $html .= '
'; $html .= tribe_events_promo_banner( false ); $this->show_data_wrapper['after'] = false; return apply_filters( 'tribe_events_view_after_html_data_wrapper', $html ); } /** * Add filters and actions */ protected function addHooks() { // Since TEC is active, change the base page for the Event Settings page Tribe__Settings::$parent_page = 'edit.php'; // Load Rewrite add_action( 'plugins_loaded', array( Tribe__Events__Rewrite::instance(), 'hooks' ) ); add_action( 'init', array( $this, 'init' ), 10 ); add_action( 'admin_init', array( $this, 'admin_init' ) ); // Frontend Javascript add_action( 'wp_enqueue_scripts', array( $this, 'loadStyle' ) ); add_filter( 'tribe_events_before_html', array( $this, 'before_html_data_wrapper' ) ); add_filter( 'tribe_events_after_html', array( $this, 'after_html_data_wrapper' ) ); // Styling add_filter( 'post_class', array( $this, 'post_class' ) ); add_filter( 'body_class', array( $this, 'body_class' ) ); add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) ); add_filter( 'post_type_archive_link', array( $this, 'event_archive_link' ), 10, 2 ); add_filter( 'query_vars', array( $this, 'eventQueryVars' ) ); add_filter( 'bloginfo_rss', array( $this, 'add_space_to_rss' ) ); add_filter( 'post_updated_messages', array( $this, 'updatePostMessage' ) ); /* Add nav menu item - thanks to http://wordpress.org/extend/plugins/cpt-archives-in-nav-menus/ */ add_filter( 'nav_menu_items_' . self::POSTTYPE, array( $this, 'add_events_checkbox_to_menu' ), null, 3 ); add_filter( 'wp_nav_menu_objects', array( $this, 'add_current_menu_item_class_to_events' ), null, 2 ); add_filter( 'template_redirect', array( $this, 'redirect_past_upcoming_view_urls' ), 11 ); /* Setup Tribe Events Bar */ add_filter( 'tribe-events-bar-views', array( $this, 'setup_listview_in_bar' ), 1, 1 ); add_filter( 'tribe-events-bar-views', array( $this, 'setup_gridview_in_bar' ), 5, 1 ); add_filter( 'tribe-events-bar-views', array( $this, 'setup_dayview_in_bar' ), 15, 1 ); add_filter( 'tribe-events-bar-filters', array( $this, 'setup_date_search_in_bar' ), 1, 1 ); add_filter( 'tribe-events-bar-filters', array( $this, 'setup_keyword_search_in_bar' ), 1, 1 ); add_filter( 'tribe-events-bar-views', array( $this, 'remove_hidden_views' ), 9999, 2 ); /* End Setup Tribe Events Bar */ add_action( 'admin_menu', array( $this, 'addEventBox' ) ); add_action( 'wp_insert_post', array( $this, 'addPostOrigin' ), 10, 2 ); add_action( 'save_post', array( $this, 'addEventMeta' ), 15, 2 ); /* Registers the list widget */ add_action( 'widgets_init', array( $this, 'register_list_widget' ), 90 ); add_action( 'save_post_' . self::VENUE_POST_TYPE, array( $this, 'save_venue_data' ), 16, 2 ); add_action( 'save_post_' . self::ORGANIZER_POST_TYPE, array( $this, 'save_organizer_data' ), 16, 2 ); add_action( 'save_post_' . self::POSTTYPE, array( $this, 'maybe_update_known_range' ) ); add_action( 'tribe_events_csv_import_complete', array( $this, 'rebuild_known_range' ) ); add_action( 'publish_' . self::POSTTYPE, array( $this, 'publishAssociatedTypes' ), 25, 2 ); add_action( 'delete_post', array( $this, 'maybe_rebuild_known_range' ) ); add_action( 'parse_query', array( $this, 'setDisplay' ), 51, 0 ); add_action( 'tribe_events_post_errors', array( 'Tribe__Events__Post_Exception', 'displayMessage' ) ); add_action( 'tribe_settings_top', array( 'Tribe__Events__Options_Exception', 'displayMessage' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_assets' ) ); add_filter( 'tribe_events_register_event_type_args', array( $this, 'setDashicon' ) ); add_action( 'trash_' . self::VENUE_POST_TYPE, array( $this, 'cleanupPostVenues' ) ); add_action( 'trash_' . self::ORGANIZER_POST_TYPE, array( $this, 'cleanupPostOrganizers' ) ); add_action( 'wp_ajax_tribe_event_validation', array( $this, 'ajax_form_validate' ) ); add_action( 'plugins_loaded', array( 'Tribe__Cache_Listener', 'instance' ) ); add_action( 'plugins_loaded', array( 'Tribe__Cache', 'setup' ) ); add_action( 'plugins_loaded', array( 'Tribe__Support', 'getInstance' ) ); add_action( 'plugins_loaded', array( $this, 'set_meta_factory_global' ) ); add_action( 'current_screen', array( $this, 'init_admin_list_screen' ) ); // Load organizer and venue editors add_action( 'admin_menu', array( $this, 'addVenueAndOrganizerEditor' ) ); add_action( 'tribe_venue_table_top', array( $this, 'displayEventVenueDropdown' ) ); add_action( 'tribe_venue_table_top', array( $this, 'display_rich_snippets_helper' ), 5 ); add_action( 'template_redirect', array( $this, 'template_redirect' ) ); add_action( 'wp', array( $this, 'issue_noindex' ) ); add_action( 'plugin_row_meta', array( $this, 'addMetaLinks' ), 10, 2 ); // organizer and venue if ( ! defined( 'TRIBE_HIDE_UPSELL' ) || ! TRIBE_HIDE_UPSELL ) { add_action( 'wp_dashboard_setup', array( $this, 'dashboardWidget' ) ); add_action( 'tribe_events_cost_table', array( $this, 'maybeShowMetaUpsell' ) ); } // option pages add_action( '_network_admin_menu', array( $this, 'initOptions' ) ); add_action( '_admin_menu', array( $this, 'initOptions' ) ); add_action( 'load-tribe_events_page_' . Tribe__Settings::$parent_slug, array( 'Tribe__Events__Amalgamator', 'listen_for_migration_button' ), 10, 0 ); add_action( 'tribe_settings_after_save', array( $this, 'flushRewriteRules' ) ); add_action( 'load-edit-tags.php', array( $this, 'prepare_to_fix_tagcloud_links' ), 10, 0 ); add_action( 'update_option_' . Tribe__Main::OPTIONNAME, array( $this, 'fix_all_day_events' ), 10, 2 ); // Check for a page that might conflict with events archive add_action( 'admin_init', array( Tribe__Admin__Notice__Archive_Slug_Conflict::instance(), 'maybe_add_admin_notice' ) ); // add-on compatibility if ( is_multisite() ) { add_action( 'network_admin_notices', array( $this, 'checkAddOnCompatibility' ) ); } else { add_action( 'admin_notices', array( $this, 'checkAddOnCompatibility' ) ); } add_action( 'wp_before_admin_bar_render', array( $this, 'addToolbarItems' ), 10 ); add_action( 'all_admin_notices', array( $this, 'addViewCalendar' ) ); add_action( 'admin_head', array( $this, 'setInitialMenuMetaBoxes' ), 500 ); add_action( 'plugin_action_links_' . trailingslashit( $this->plugin_dir ) . 'the-events-calendar.php', array( $this, 'addLinksToPluginActions' ) ); // override default wp_terms_checklist arguments to prevent checked items from bubbling to the top. Instead, retain hierarchy. add_filter( 'wp_terms_checklist_args', array( $this, 'prevent_checked_on_top_terms' ), 10, 2 ); add_action( 'tribe_events_pre_get_posts', array( $this, 'set_tribe_paged' ) ); // Upgrade material. add_action( 'init', array( $this, 'run_updates' ), 0, 0 ); if ( defined( 'WP_LOAD_IMPORTERS' ) && WP_LOAD_IMPORTERS ) { add_filter( 'wp_import_post_data_raw', array( $this, 'filter_wp_import_data_before' ), 10, 1 ); add_filter( 'wp_import_post_data_processed', array( $this, 'filter_wp_import_data_after' ), 10, 1 ); } add_action( 'plugins_loaded', array( $this, 'init_ical' ), 2, 0 ); add_action( 'plugins_loaded', array( $this, 'init_day_view' ), 2 ); add_action( 'plugins_loaded', array( 'Tribe__Events__Bar', 'instance' ) ); add_action( 'plugins_loaded', array( 'Tribe__Events__Templates', 'init' ) ); add_action( 'init', array( $this, 'filter_cron_schedules' ) ); // Add support for tickets plugin add_action( 'tribe_tickets_ticket_added', array( 'Tribe__Events__API', 'update_event_cost' ) ); add_action( 'tribe_tickets_ticket_deleted', array( 'Tribe__Events__API', 'update_event_cost' ) ); add_filter( 'tribe_tickets_default_end_date', array( $this, 'default_end_date_for_tickets' ), 10, 2 ); add_filter( 'tribe_post_types', array( $this, 'filter_post_types' ) ); add_filter( 'tribe_is_post_type_screen_post_types', array( $this, 'is_post_type_screen_post_types' ) ); add_filter( 'tribe_currency_symbol', array( $this, 'maybe_set_currency_symbol_with_post' ), 10, 2 ); add_filter( 'tribe_reverse_currency_position', array( $this, 'maybe_set_currency_position_with_post' ), 10, 2 ); // Settings page hooks add_action( 'tribe_settings_do_tabs', array( $this, 'do_addons_api_settings_tab' ) ); add_filter( 'tribe_general_settings_tab_fields', array( $this, 'general_settings_tab_fields' ) ); add_filter( 'tribe_display_settings_tab_fields', array( $this, 'display_settings_tab_fields' ) ); add_filter( 'tribe_settings_url', array( $this, 'tribe_settings_url' ) ); // Setup Help Tab texting add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_feature_box_content' ) ); add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_support_content' ) ); add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_extra_content' ) ); } /** * 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 apply_filters( 'tribe_venue_label_plural', esc_html__( 'Venues', 'the-events-calendar' ) ); } /** * Allow users to specify their own singular label for Venues * @return string */ public function get_venue_label_singular() { return apply_filters( 'tribe_venue_label_singular', esc_html__( 'Venue', 'the-events-calendar' ) ); } /** * Allow users to specify their own plural label for Organizers * @return string */ public function get_organizer_label_plural() { return apply_filters( 'tribe_organizer_label_plural', esc_html__( 'Organizers', 'the-events-calendar' ) ); } /** * Allow users to specify their own singular label for Organizers * @return string */ public function get_organizer_label_singular() { return apply_filters( 'tribe_organizer_label_singular', esc_html__( 'Organizer', 'the-events-calendar' ) ); } /** * 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() { $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->postTypeArgs['rewrite']['slug'] = sanitize_title( $this->rewriteSlugSingular ); $this->postVenueTypeArgs['rewrite']['slug'] = sanitize_title( $this->singular_venue_label ); $this->postVenueTypeArgs['show_in_nav_menus'] = class_exists( 'Tribe__Events__Pro__Main' ) ? true : false; $this->postOrganizerTypeArgs['rewrite']['slug'] = sanitize_title( $this->singular_organizer_label ); $this->postOrganizerTypeArgs['show_in_nav_menus'] = class_exists( 'Tribe__Events__Pro__Main' ) ? true : false; $this->postVenueTypeArgs['public'] = class_exists( 'Tribe__Events__Pro__Main' ) ? true : false; $this->postOrganizerTypeArgs['public'] = class_exists( 'Tribe__Events__Pro__Main' ) ? true : 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() { $this->timezone_settings = new Tribe__Events__Admin__Timezone_Settings; } /** * 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, '<' ) ) { $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 .= '
'; $link = add_query_arg( array( 'utm_campaign' => 'in-app', 'utm_medium' => 'plugin-tec', 'utm_source' => 'notice', ), self::$tecUrl . 'knowledgebase/version-compatibility/' ); $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 */ public function initOptions() { Tribe__Events__Activation_Page::init(); } /** * 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']; 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 /** * 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'; } /** * Registers the license key management tab in the Events > Settings screen, * only if premium addons are detected. */ protected function do_licenses_tab() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::do_licenses_tab' ); Tribe__Settings_Manager::instance()->do_licenses_tab(); } /** * Tries to discover if licensable addons are activated on the same site. * * @return bool */ protected function have_addons() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::have_addons' ); return Tribe__Settings_Manager::instance()->have_addons(); } /** * 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' ) . '

'; } if ( ! self::supportedVersion( 'php' ) ) { echo '

' . 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(); array_unshift( $posts, (object) array( 'ID' => 0, 'object_id' => $_nav_menu_placeholder, 'post_content' => '', 'post_excerpt' => '', 'post_title' => $post_type['args']->labels->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 ) ); register_post_type( self::VENUE_POST_TYPE, apply_filters( 'tribe_events_register_venue_type_args', $this->postVenueTypeArgs ) ); register_post_type( self::ORGANIZER_POST_TYPE, apply_filters( 'tribe_events_register_organizer_type_args', $this->postOrganizerTypeArgs ) ); 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 $this->postVenueTypeArgs; } /** * Get organizer post type args * * @return array */ public function getOrganizerPostTypeArgs() { return $this->postOrganizerTypeArgs; } /** * 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' ), strtolower( $this->plural_event_label ) ), 'not_found_in_trash' => sprintf( esc_html__( 'No %s found in Trash', 'the-events-calendar' ), strtolower( $this->plural_event_label ) ), ) ); /** * Provides an opportunity to modify the labels used for the venue post type. * * @var array */ $this->postVenueTypeArgs['labels'] = apply_filters( 'tribe_events_register_venue_post_type_labels', array( 'name' => $this->plural_venue_label, 'singular_name' => $this->singular_venue_label, 'add_new' => esc_html__( 'Add New', 'the-events-calendar' ), 'add_new_item' => sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_venue_label ), 'edit_item' => sprintf( esc_html__( 'Edit %s', 'the-events-calendar' ), $this->singular_venue_label ), 'new_item' => sprintf( esc_html__( 'New %s', 'the-events-calendar' ), $this->singular_venue_label ), 'view_item' => sprintf( esc_html__( 'View %s', 'the-events-calendar' ), $this->singular_venue_label ), 'search_items' => sprintf( esc_html__( 'Search %s', 'the-events-calendar' ), $this->plural_venue_label ), 'not_found' => sprintf( esc_html__( 'No %s found', 'the-events-calendar' ), strtolower( $this->plural_venue_label ) ), 'not_found_in_trash' => sprintf( esc_html__( 'No %s found in Trash', 'the-events-calendar' ), strtolower( $this->plural_venue_label ) ), ) ); /** * Provides an opportunity to modify the labels used for the organizer post type. * * @var array */ $this->postOrganizerTypeArgs['labels'] = apply_filters( 'tribe_events_register_organizer_post_type_labels', array( 'name' => $this->plural_organizer_label, 'singular_name' => $this->singular_organizer_label, 'add_new' => esc_html__( 'Add New', 'the-events-calendar' ), 'add_new_item' => sprintf( esc_html__( 'Add New %s', 'the-events-calendar' ), $this->singular_organizer_label ), 'edit_item' => sprintf( esc_html__( 'Edit %s', 'the-events-calendar' ), $this->singular_organizer_label ), 'new_item' => sprintf( esc_html__( 'New %s', 'the-events-calendar' ), $this->singular_organizer_label ), 'view_item' => sprintf( esc_html__( 'View %s', 'the-events-calendar' ), $this->singular_organizer_label ), 'search_items' => sprintf( esc_html__( 'Search %s', 'the-events-calendar' ), $this->plural_organizer_label ), 'not_found' => sprintf( esc_html__( 'No %s found', 'the-events-calendar' ), strtolower( $this->plural_organizer_label ) ), 'not_found_in_trash' => sprintf( esc_html__( 'No %s found in Trash', 'the-events-calendar' ), strtolower( $this->plural_organizer_label ) ), ) ); /** * 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' ), '', strtolower( $this->singular_event_label ) . '' ), 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, '', strtolower( $this->singular_event_label ) . '' ), 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 ) ) . '', '', strtolower( $this->singular_event_label ) . '' ), 10 => sprintf( esc_html__( '%1$s draft updated. %2$sPreview %3$s', 'the-events-calendar' ), $this->singular_event_label, '', strtolower( $this->singular_event_label ) . '' ), ); $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 ); if ( ( ! $post_id || get_post_status( $post_id ) === 'auto-draft' ) && ! $venue_id && tribe_is_community_edit_event_page() ) { $venue_id = $this->defaults()->venue_id(); } $venue_id = apply_filters( 'tribe_display_event_venue_dropdown_id', $venue_id ); ?> singular_venue_label ); ?> saved_venues_dropdown( $venue_id ); $venue_pto = get_post_type_object( self::VENUE_POST_TYPE ); if ( current_user_can( $venue_pto->cap->edit_posts ) ) { ?> 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; } ?> ', '' ) ?> defaults()->organizer_id(); } $current_organizer = apply_filters( 'tribe_display_event_organizer_dropdown_id', $current_organizer ); ?> saved_organizers_dropdown( $current_organizer ); ?> ID ) { $my_venues = $this->get_venue_info( null, array( 'post_status' => array( 'publish', 'draft', 'private', 'pending', ), 'author' => $current_user->ID, ) ); if ( ! empty( $my_venues ) ) { foreach ( $my_venues as $my_venue ) { $my_venue_ids[] = $my_venue->ID; $venue_title = wp_kses( get_the_title( $my_venue->ID ), array() ); $my_venue_options .= ''; } } } if ( current_user_can( 'edit_others_tribe_venues' ) ) { $venues = $this->get_venue_info( null, array( 'post_status' => array( 'publish', 'draft', 'private', 'pending', ), 'post__not_in' => $my_venue_ids, ) ); } else { $venues = $this->get_venue_info( null, array( 'post_status' => 'publish', 'post__not_in' => $my_venue_ids, ) ); } if ( $venues || $my_venues ) { $venue_pto = get_post_type_object( self::VENUE_POST_TYPE ); echo ''; } else { echo '

' . sprintf( esc_html__( 'No saved %s exists.', 'the-events-calendar' ), strtolower( $this->singular_venue_label ) ) . '

'; } } /** * helper function for displaying the saved organizer dropdown * Used to be a PRO only feature, but as of 3.0, it is part of Core. * * @param mixed $current the current saved venue * @param string $name the name value for the field */ public function saved_organizers_dropdown( $current = null, $name = 'organizer[OrganizerID]' ) { $my_organizer_ids = array(); $current_user = wp_get_current_user(); $my_organizers = false; $my_organizers_options = ''; if ( 0 != $current_user->ID ) { $my_organizers = $this->get_organizer_info( null, array( 'post_status' => array( 'publish', 'draft', 'private', 'pending', ), 'author' => $current_user->ID, ) ); if ( ! empty( $my_organizers ) ) { foreach ( $my_organizers as $my_organizer ) { $my_organizer_ids[] = $my_organizer->ID; $organizer_title = wp_kses( get_the_title( $my_organizer->ID ), array() ); $my_organizers_options .= ''; } } } if ( current_user_can( 'edit_others_tribe_organizers' ) ) { $organizers = $this->get_organizer_info( null, array( 'post_status' => array( 'publish', 'draft', 'private', 'pending', ), 'post__not_in' => $my_organizer_ids, ) ); } else { $organizers = $this->get_organizer_info( null, array( 'post_status' => 'publish', 'post__not_in' => $my_organizer_ids, ) ); } if ( $organizers || $my_organizers ) { $oganizer_pto = get_post_type_object( self::ORGANIZER_POST_TYPE ); echo ''; } else { echo '

' . sprintf( esc_html__( 'No saved %s exists.', 'the-events-calendar' ), strtolower( $this->singular_organizer_label ) ) . '

'; printf( '', esc_attr( $name ), 0 ); } } /** * override default wp_terms_checklist arguments to prevent checked items from bubbling to the * top. Instead, retain hierarchy. */ public function prevent_checked_on_top_terms( $args, $post_id ) { $post = get_post( $post_id ); if ( ! tribe_is_event( $post ) ) { return $args; } $args['checked_ontop'] = false; return $args; }//end prevent_checked_on_top_terms /** * Update admin classes * * @param array $classes * * @return array */ public function admin_body_class( $classes ) { $admin_helpers = Tribe__Admin__Helpers::instance(); if ( $admin_helpers->is_screen( 'settings_page_tribe-settings' ) || $admin_helpers->is_post_type_screen() ) { $classes .= ' events-cal '; } return $classes; } /** * Add admin scripts and styles * */ public function add_admin_assets() { $admin_helpers = Tribe__Admin__Helpers::instance(); // setup plugin resources & 3rd party vendor urls $vendor_url = trailingslashit( $this->plugin_url ) . 'vendor/'; // admin stylesheet - only load admin stylesheet when on Tribe pages if ( $admin_helpers->is_screen() ) { wp_enqueue_style( self::POSTTYPE . '-admin', tribe_events_resource_url( 'events-admin.css' ), array(), apply_filters( 'tribe_events_css_version', self::VERSION ) ); } // UI admin Tribe__Events__Template_Factory::asset_package( 'admin-menu' ); // settings screen if ( $admin_helpers->is_screen( 'settings_page_tribe-settings' ) ) { // chosen Tribe__Events__Template_Factory::asset_package( 'chosen' ); // JS admin Tribe__Events__Template_Factory::asset_package( 'admin' ); // JS settings Tribe__Events__Template_Factory::asset_package( 'settings' ); wp_enqueue_script( 'thickbox' ); wp_enqueue_style( 'thickbox' ); // hook for other plugins do_action( 'tribe_settings_enqueue' ); } if ( $admin_helpers->is_screen( 'widgets' ) ) { Tribe__Events__Template_Factory::asset_package( 'chosen' ); } // events, organizer, or venue editing if ( $admin_helpers->is_post_type_screen() ) { // chosen Tribe__Events__Template_Factory::asset_package( 'chosen' ); // select 2 Tribe__Events__Template_Factory::asset_package( 'select2' ); // date picker Tribe__Events__Template_Factory::asset_package( 'datepicker' ); // dialog Tribe__Events__Template_Factory::asset_package( 'dialog' ); // UI admin Tribe__Events__Template_Factory::asset_package( 'admin-ui' ); // JS admin Tribe__Events__Template_Factory::asset_package( 'admin' ); // ecp placeholders Tribe__Events__Template_Factory::asset_package( 'ecp-plugins' ); if ( $admin_helpers->is_post_type_screen( self::POSTTYPE ) ){ add_action( 'admin_footer', array( $this, 'printLocalizedAdmin' ) ); // hook for other plugins do_action( 'tribe_events_enqueue' ); } elseif ( $admin_helpers->is_post_type_screen( self::VENUE_POST_TYPE ) ){ // hook for other plugins do_action( 'tribe_venues_enqueue' ); } elseif ( $admin_helpers->is_post_type_screen( self::ORGANIZER_POST_TYPE ) ){ do_action( 'tribe_organizers_enqueue' ); } } } /** * Modify the post type args to set Dashicon if we're in WP 3.8+ * * @return array post type args **/ public function setDashicon( $postTypeArgs ) { global $wp_version; if ( version_compare( $wp_version, 3.8 ) >= 0 ) { $postTypeArgs['menu_icon'] = 'dashicons-calendar'; } return $postTypeArgs; } /** * Localize admin * * @return array */ public function localizeAdmin() { $bits = array( 'dayNames' => $this->daysOfWeek, 'dayNamesShort' => $this->daysOfWeekShort, 'dayNamesMin' => $this->daysOfWeekMin, 'monthNames' => array_values( $this->monthNames() ), 'monthNamesShort' => array_values( $this->monthNames( true ) ), 'nextText' => esc_html__( 'Next', 'the-events-calendar' ), 'prevText' => esc_html__( 'Prev', 'the-events-calendar' ), 'currentText' => esc_html__( 'Today', 'the-events-calendar' ), 'closeText' => esc_html__( 'Done', 'the-events-calendar' ), ); return $bits; } /** * Output localized admin javascript * */ public function printLocalizedAdmin() { wp_localize_script( 'tribe-events-admin', 'TEC', $this->localizeAdmin() ); } /** * Get all options for the Events Calendar * * @return array of options */ public static function getOptions() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::get_options' ); return Tribe__Settings_Manager::get_options(); } /** * Get value for a specific option * * @param string $optionName name of option * @param string $default default value * * @return mixed results of option query */ public static function getOption( $optionName, $default = '' ) { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::get_option' ); return Tribe__Settings_Manager::get_option( $optionName, $default ); } /** * Saves the options for the plugin * * @param array $options formatted the same as from getOptions() * @param bool $apply_filters * */ public function setOptions( $options, $apply_filters = true ) { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::set_options' ); Tribe__Settings_Manager::set_options( $options, $apply_filters ); } /** * Set an option * * @param string $name * @param mixed $value * */ public function setOption( $name, $value ) { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::set_option' ); Tribe__Settings_Manager::set_option( $name, $value ); } /** * Get all network options for the Events Calendar * * @return array of options */ public static function getNetworkOptions() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::get_network_options' ); return Tribe__Settings_Manager::get_network_options(); } /** * Get value for a specific network option * * @param string $optionName name of option * @param string $default default value * * @return mixed results of option query */ public function getNetworkOption( $optionName, $default = '' ) { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::get_network_option' ); return Tribe__Settings_Manager::get_network_option( $optionName, $default ); } /** * Saves the network options for the plugin * * @param array $options formatted the same as from getOptions() * @param bool $apply_filters * */ public function setNetworkOptions( $options, $apply_filters = true ) { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::set_network_options' ); Tribe__Settings_Manager::set_network_options( $options, $apply_filters ); } /** * Add the network admin options page * */ public function addNetworkOptionsPage() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::add_network_options_page' ); Tribe__Settings_Manager::add_network_options_page(); } /** * Render network admin options view * */ public function doNetworkSettingTab() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::do_network_settings_tab' ); Tribe__Settings_Manager::do_network_settings_tab(); } /** * Filters the post types across all of the Tribe plugins */ public function filter_post_types( $post_types ) { $post_types[] = self::POSTTYPE; $post_types[] = self::ORGANIZER_POST_TYPE; $post_types[] = self::VENUE_POST_TYPE; return $post_types; } /** * Get the post types that are associated with TEC. * * @return array The post types associated with this plugin */ public static function getPostTypes() { return apply_filters( 'tribe_events_post_types', Tribe__Main::get_post_types() ); } /** * An event can have one or more start dates. This gives * the earliest of those. * * @param int $post_id * * @return string The date string for the earliest occurrence of the event */ public static function get_series_start_date( $post_id ) { if ( function_exists( 'tribe_get_recurrence_start_dates' ) ) { $start_dates = tribe_get_recurrence_start_dates( $post_id ); return reset( $start_dates ); } else { return get_post_meta( $post_id, '_EventStartDate', true ); } } /** * Save hidden tabs * */ public function saveAllTabsHidden() { _deprecated_function( __METHOD__, '4.0', 'Tribe__Settings_Manager::save_all_tabs_hidden' ); Tribe__Settings_Manager::instance()->save_all_tabs_hidden(); } /** * Clean up trashed venues * * @param int $postId * */ public function cleanupPostVenues( $postId ) { $this->removeDeletedPostTypeAssociation( '_EventVenueID', $postId ); } /** * Clean up trashed organizers. * * @param int $postId * */ public function cleanupPostOrganizers( $postId ) { $this->removeDeletedPostTypeAssociation( '_EventOrganizerID', $postId ); } /** * Clean up trashed venues or organizers. * * @param string $key * @param int $postId * */ protected function removeDeletedPostTypeAssociation( $key, $postId ) { $the_query = new WP_Query( array( 'meta_key' => $key, 'meta_value' => $postId, 'post_type' => self::POSTTYPE, ) ); while ( $the_query->have_posts() ): $the_query->the_post(); delete_post_meta( get_the_ID(), $key ); endwhile; wp_reset_postdata(); } /** * Truncate a given string. * * @deprecated * @todo remove on 4.3 * * @param string $text The text to truncate. * @param int $excerpt_length How long you want it to be truncated to. * * @return string The truncated text. */ public function truncate( $text, $excerpt_length = 44 ) { _deprecated_function( __FUNCTION__, '4.0', 'tribe_events_get_the_excerpt()' ); $text = apply_filters( 'the_content', $text ); $text = str_replace( ']]>', ']]>', $text ); $text = strip_tags( $text ); $words = explode( ' ', $text, $excerpt_length + 1 ); if ( count( $words ) > $excerpt_length ) { array_pop( $words ); $text = implode( ' ', $words ); $text = rtrim( $text ); $text .= '…'; } return $text; } /** * Load the text domain. * */ public function loadTextDomain() { load_plugin_textdomain( 'the-events-calendar', false, $this->plugin_dir . 'lang/' ); // Setup the l10n strings $this->setup_l10n_strings(); } /** * Load asset packages. * */ public function loadStyle() { if ( tribe_is_event_query() || tribe_is_event_organizer() || tribe_is_event_venue() ) { // jquery-resize Tribe__Events__Template_Factory::asset_package( 'jquery-resize' ); // smoothness Tribe__Events__Template_Factory::asset_package( 'smoothness' ); // Tribe Calendar JS Tribe__Events__Template_Factory::asset_package( 'calendar-script' ); Tribe__Events__Template_Factory::asset_package( 'events-css' ); } else { if ( is_active_widget( false, false, 'tribe-events-list-widget' ) ) { Tribe__Events__Template_Factory::asset_package( 'events-css' ); } } } /** * Initializes admin-specific items for the events admin list dashboard page. Hooked to the * current_screen action * * @param WP_Screen $screen WP Admin screen object for the current page */ public function init_admin_list_screen( $screen ) { if ( 'edit' !== $screen->base ) { return; } if ( self::POSTTYPE !== $screen->post_type ) { return; } Tribe__Events__Admin_List::init(); } /** * Set the displaying class property. * */ public function setDisplay() { if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) { $this->displaying = 'admin'; } else { global $wp_query; if ( $wp_query && $wp_query->is_main_query() && ! empty( $wp_query->tribe_is_event_query ) ) { $this->displaying = isset( $wp_query->query_vars['eventDisplay'] ) ? $wp_query->query_vars['eventDisplay'] : tribe_get_option( 'viewOption', 'list' ); if ( is_single() && $this->displaying != 'all' ) { $this->displaying = 'single-event'; } } } } /** * Returns the default view, providing a fallback if the default is no longer availble. * * This can be useful is for instance a view added by another plugin (such as PRO) is * stored as the default but can no longer be generated due to the plugin being deactivated. * * @return string */ public function default_view() { // Compare the stored default view option to the list of available views $default = Tribe__Settings_Manager::instance()->get_option( 'viewOption', 'month' ); $available_views = (array) apply_filters( 'tribe-events-bar-views', array(), false ); foreach ( $available_views as $view ) { if ( $default === $view['displaying'] ) { return $default; } } // If the stored option is no longer available, pick the first available one instead $first_view = array_shift( $available_views ); $view = $first_view['displaying']; // Update the saved option Tribe__Settings_Manager::instance()->set_option( 'viewOption', $view ); return $view; } protected function setup_l10n_strings() { global $wp_locale; // Localize month names $this->monthsFull = array( 'January' => $wp_locale->get_month( '01' ), 'February' => $wp_locale->get_month( '02' ), 'March' => $wp_locale->get_month( '03' ), 'April' => $wp_locale->get_month( '04' ), 'May' => $wp_locale->get_month( '05' ), 'June' => $wp_locale->get_month( '06' ), 'July' => $wp_locale->get_month( '07' ), 'August' => $wp_locale->get_month( '08' ), 'September' => $wp_locale->get_month( '09' ), 'October' => $wp_locale->get_month( '10' ), 'November' => $wp_locale->get_month( '11' ), 'December' => $wp_locale->get_month( '12' ), ); // yes, it's awkward. easier this way than changing logic elsewhere. $this->monthsShort = $months = array( 'Jan' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '01' ) ), 'Feb' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '02' ) ), 'Mar' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '03' ) ), 'Apr' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '04' ) ), 'May' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '05' ) ), 'Jun' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '06' ) ), 'Jul' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '07' ) ), 'Aug' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '08' ) ), 'Sep' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '09' ) ), 'Oct' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '10' ) ), 'Nov' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '11' ) ), 'Dec' => $wp_locale->get_month_abbrev( $wp_locale->get_month( '12' ) ), ); // Get the localized weekday names for ( $i = 0; $i <= 6; $i ++ ) { $day = $wp_locale->get_weekday( $i ); $this->daysOfWeek[ $i ] = $day; $this->daysOfWeekShort[ $i ] = $wp_locale->get_weekday_abbrev( $day ); $this->daysOfWeekMin[ $i ] = $wp_locale->get_weekday_initial( $day ); } // Setup the Strings for Rewrite Translations __( 'tag', 'the-events-calendar' ); __( 'category', 'the-events-calendar' ); __( 'page', 'the-events-calendar' ); __( 'event', 'the-events-calendar' ); __( 'events', 'the-events-calendar' ); __( 'all', 'the-events-calendar' ); } /** * Helper method to return an array of translated month names or short month names * * @param bool $short * * @return array Translated month names */ public function monthNames( $short = false ) { if ( $short ) { return $this->monthsShort; } return $this->monthsFull; } /** * Flush rewrite rules to support custom links * * @todo This is only registering the events post type, not the meta types * * @link http://codex.wordpress.org/Custom_Queries#Permalinks_for_Custom_Archives */ public static function flushRewriteRules() { $tec = self::instance(); // reregister custom post type to make sure slugs are updated $tec->postTypeArgs['rewrite']['slug'] = sanitize_title( $tec->getRewriteSlugSingular() ); register_post_type( self::POSTTYPE, apply_filters( 'tribe_events_register_event_type_args', $tec->postTypeArgs ) ); add_action( 'shutdown', 'flush_rewrite_rules' ); } /** * If a themer usees get_post_type_archive_link() to find the event archive URL, this * ensures they get the correct result. * * @param string $link * @param string $post_type * @return string */ public function event_archive_link( $link, $post_type ) { return ( self::POSTTYPE === $post_type ) ? tribe_get_events_link() : $link; } /** * Adds the event specific query vars to WordPress * * @param array $qvars * * @link http://codex.wordpress.org/Custom_Queries#Permalinks_for_Custom_Archives * @return mixed array of query variables that this plugin understands */ public function eventQueryVars( $qvars ) { $qvars[] = 'eventDisplay'; $qvars[] = 'eventDate'; $qvars[] = 'ical'; $qvars[] = 'start_date'; $qvars[] = 'end_date'; $qvars[] = self::TAXONOMY; return $qvars; } /** * Get all possible translations for a String based on the given Languages and Domains * * WARNING: This function is slow because it deals with files, so don't overuse it! * * @todo Include support for the `load_theme_textdomain` + `load_muplugin_textdomain` * * @param array $strings An array of strings (required) * @param array $languages Which l10n to fetch the string (required) * @param array $domains Possible Domains to re-load * @param string $default_language The default language to avoid re-doing that * * @return array A multi level array with the possible translations for the given strings */ public function get_i18n_strings( $strings, $languages, $domains = array(), $default_language = 'en_US' ) { $domains = wp_parse_args( $domains, array( 'default' => true, // Default doesn't need file path 'the-events-calendar' => $this->plugin_dir . 'lang/', ) ); foreach ( $languages as $language ) { foreach ( (array) $domains as $domain => $file ) { // Configure the language $this->_locale = $language; add_filter( 'locale', array( $this, '_set_locale' ) ); // Reload it with the correct language unload_textdomain( $domain ); if ( 'default' === $domain ) { load_default_textdomain(); } else { load_plugin_textdomain( $domain, false, $file ); } // Loop on the strings the build the possible translations foreach ( $strings as $key => $value ) { $value = is_array( $value ) ? reset( $value ) : $value; if ( ! is_string( $value ) ) { continue; } // Make sure we have an Array $strings[ $key ] = (array) $strings[ $key ]; // Grab the possible strings for Default and Any other domain if ( 'default' === $domain ) { $strings[ $key ][] = __( $value ); $strings[ $key ][] = __( strtolower( $value ) ); $strings[ $key ][] = __( ucfirst( $value ) ); } else { $strings[ $key ][] = __( $value, $domain ); $strings[ $key ][] = __( strtolower( $value ), $domain ); $strings[ $key ][] = __( ucfirst( $value ), $domain ); } } // Set back to the default language remove_filter( 'locale', array( $this, '_set_locale' ) ); // Reload it with the correct language unload_textdomain( $domain ); if ( 'default' === $domain ) { load_default_textdomain(); } else { load_plugin_textdomain( $domain, false, $file ); } } } // Prevent Empty Strings and Duplicates foreach ( $strings as $key => $value ) { $strings[ $key ] = array_filter( array_unique( array_map( 'sanitize_title_with_dashes', $value ) ) ); } return $strings; } /** * DO NOT USE THIS INTERNAL USE * A way to quickly filter the locale based on a Local Class Variable * * @return string The Locale set on _locale */ public function _set_locale() { return empty( $this->_locale ) ? 'en_US' : $this->_locale; } /** * Redirect the legacy past/upcoming view URLs to list */ public function redirect_past_upcoming_view_urls() { if ( strpos( $_SERVER['REQUEST_URI'], $this->getRewriteSlug() . '/' . $this->pastSlug ) !== false ) { wp_redirect( esc_url_raw( add_query_arg( array( 'tribe_event_display' => 'past' ), str_replace( '/' . $this->pastSlug . '/', '/' . $this->listSlug . '/', $_SERVER['REQUEST_URI'] ) ) ) ); die; } elseif ( strpos( $_SERVER['REQUEST_URI'], $this->getRewriteSlug() . '/' . $this->upcomingSlug ) !== false ) { wp_redirect( str_replace( '/' . $this->upcomingSlug . '/', '/' . $this->listSlug . '/', $_SERVER['REQUEST_URI'] ) ); die; } } /** * Returns various internal events-related URLs * * @param string $type type of link. See switch statement for types. * @param string $secondary for $type = month, pass a YYYY-MM string for a specific month's URL * for $type = week, pass a Week # string for a specific week's URL * @param int|bool|null $term * * @return string The link. */ public function getLink( $type = 'home', $secondary = false, $term = null ) { // if permalinks are off or user doesn't want them: ugly. if ( '' === get_option( 'permalink_structure' ) ) { return esc_url_raw( $this->uglyLink( $type, $secondary ) ); } // account for semi-pretty permalinks if ( false !== strpos( get_option( 'permalink_structure' ), 'index.php' ) ) { $event_url = home_url( '/index.php/' ); } else { $event_url = home_url( '/' ); } // URL Arguments on home_url() pre-check $url_query = @parse_url( $event_url, PHP_URL_QUERY ); $url_args = wp_parse_args( $url_query, array() ); // Remove the "args" if ( ! empty( $url_query ) ) { $event_url = str_replace( '?' . $url_query, '', $event_url ); } // Append Events structure $event_url .= trailingslashit( sanitize_title( Tribe__Settings_Manager::get_option( 'eventsSlug', 'events' ) ) ); // if we're on an Event Cat, show the cat link, except for home and days. if ( $type !== 'home' && is_tax( self::TAXONOMY ) && $term !== false && ! is_numeric( $term ) ) { $term_link = get_term_link( get_query_var( 'term' ), self::TAXONOMY ); if ( ! is_wp_error( $term_link ) ) { $event_url = trailingslashit( $term_link ); } } else { if ( $term ) { $term_link = get_term_link( (int) $term, self::TAXONOMY ); if ( ! is_wp_error( $term_link ) ) { $event_url = trailingslashit( $term_link ); } } } switch ( $type ) { case 'home': $event_url = trailingslashit( esc_url_raw( $event_url ) ); break; case 'month': if ( $secondary ) { $event_url = trailingslashit( esc_url_raw( $event_url . $secondary ) ); } else { $event_url = trailingslashit( esc_url_raw( $event_url . $this->monthSlug ) ); } break; case 'list': $event_url = trailingslashit( esc_url_raw( $event_url . $this->listSlug ) ); break; case 'upcoming': $event_url = trailingslashit( esc_url_raw( $event_url . $this->listSlug ) ); break; case 'past': $event_url = esc_url_raw( add_query_arg( 'tribe_event_display', 'past', trailingslashit( $event_url . $this->listSlug ) ) ); break; case 'dropdown': $event_url = esc_url_raw( $event_url ); break; case 'single': global $post; $p = $secondary ? $secondary : $post; $link = trailingslashit( get_permalink( $p ) ); $event_url = trailingslashit( esc_url_raw( $link ) ); break; case 'day': if ( empty( $secondary ) ) { $secondary = $this->todaySlug; } else { $secondary = tribe_format_date( $secondary, false, Tribe__Date_Utils::DBDATEFORMAT ); } $event_url = trailingslashit( esc_url_raw( $event_url . $secondary ) ); break; default: $event_url = esc_url_raw( $event_url ); break; } // Filter get link $event_url = apply_filters( 'tribe_events_get_link', $event_url, $type, $secondary, $term, $url_args ); // @todo deprecate on 4.2 $event_url = apply_filters( 'tribe_events_getLink', $event_url, $type, $secondary, $term, $url_args ); // Add the Arguments back $event_url = add_query_arg( $url_args, $event_url ); return $event_url; } /** * If pretty perms are off, get the ugly link. * * @param string $type The type of link requested. * @param bool|string $secondary Some secondary data for the link. * * @return string The ugly link. */ public function uglyLink( $type = 'home', $secondary = false ) { $eventUrl = add_query_arg( 'post_type', self::POSTTYPE, home_url() ); // if we're on an Event Cat, show the cat link, except for home. if ( $type !== 'home' && is_tax( self::TAXONOMY ) ) { $eventUrl = add_query_arg( self::TAXONOMY, get_query_var( 'term' ), $eventUrl ); } switch ( $type ) { case 'day': $eventUrl = add_query_arg( array( 'eventDisplay' => $type ), $eventUrl ); if ( $secondary ) { $eventUrl = add_query_arg( array( 'eventDate' => $secondary ), $eventUrl ); } break; case 'week': case 'month': $eventUrl = add_query_arg( array( 'eventDisplay' => $type ), $eventUrl ); if ( is_string( $secondary ) ) { $eventUrl = add_query_arg( array( 'eventDate' => $secondary ), $eventUrl ); } elseif ( is_array( $secondary ) ) { $eventUrl = add_query_arg( $secondary, $eventUrl ); } break; case 'list': case 'past': case 'upcoming': $eventUrl = add_query_arg( array( 'eventDisplay' => $type ), $eventUrl ); break; case 'dropdown': $dropdown = add_query_arg( array( 'eventDisplay' => 'month', 'eventDate' => ' ' ), $eventUrl ); $eventUrl = rtrim( $dropdown ); // tricksy break; case 'single': global $post; $p = $secondary ? $secondary : $post; $eventUrl = get_permalink( $p ); break; case 'home': default: break; } return apply_filters( 'tribe_events_ugly_link', $eventUrl, $type, $secondary ); } /** * Returns the GCal export link for a given event id. * * @param int $postId The post id requested. * * @return string The URL for the GCal export link. */ public function googleCalendarLink( $postId = null ) { global $post; $tribeEvents = self::instance(); if ( $postId === null || ! is_numeric( $postId ) ) { $postId = $post->ID; } // protecting for reccuring because the post object will have the start/end date available $start_date = isset( $post->EventStartDate ) ? strtotime( $post->EventStartDate ) : strtotime( get_post_meta( $postId, '_EventStartDate', true ) ); $end_date = isset( $post->EventEndDate ) ? strtotime( $post->EventEndDate . ( get_post_meta( $postId, '_EventAllDay', true ) ? ' + 1 day' : '' ) ) : strtotime( get_post_meta( $postId, '_EventEndDate', true ) . ( get_post_meta( $postId, '_EventAllDay', true ) ? ' + 1 day' : '' ) ); $dates = ( get_post_meta( $postId, '_EventAllDay', true ) ) ? date( 'Ymd', $start_date ) . '/' . date( 'Ymd', $end_date ) : date( 'Ymd', $start_date ) . 'T' . date( 'Hi00', $start_date ) . '/' . date( 'Ymd', $end_date ) . 'T' . date( 'Hi00', $end_date ); $location = trim( $tribeEvents->fullAddressString( $postId ) ); $base_url = 'http://www.google.com/calendar/event'; $event_details = apply_filters( 'the_content', get_the_content() ); // Hack: Add space after paragraph // Normally Google Cal understands the newline character %0a // And that character will automatically replace newlines on urlencode() $event_details = str_replace ( '

', '

', $event_details ); $event_details = strip_tags( $event_details ); //Truncate Event Description and add permalink if greater than 996 characters if ( strlen( $event_details ) > 996 ) { $event_url = get_permalink(); $event_details = substr( $event_details, 0, 996 ); //Only add the permalink if it's shorter than 900 characters, so we don't exceed the browser's URL limits if ( strlen( $event_url ) < 900 ) { $event_details .= sprintf( ' (View Full %1$s Description Here: %2$s)', $this->singular_event_label, $event_url ); } } $params = array( 'action' => 'TEMPLATE', 'text' => urlencode( strip_tags( $post->post_title ) ), 'dates' => $dates, 'details' => urlencode( $event_details ), 'location' => urlencode( $location ), 'trp' => 'false', 'sprop' => 'website:' . home_url(), ); $params = apply_filters( 'tribe_google_calendar_parameters', $params, $postId ); $url = add_query_arg( $params, $base_url ); return $url; } /** * Custom Escape for gCal Description to keep spacing characters in the url * * @return santized url */ public function esc_gcal_url( $url ) { $url = str_replace( '%0A', 'TRIBE-GCAL-LINEBREAK', $url ); $url = esc_url( $url ); $url = str_replace( 'TRIBE-GCAL-LINEBREAK', '%0A', $url ); return $url; } /** * Returns a link to google maps for the given event. This link can be filtered * using the tribe_events_google_map_link hook. * * @param int|null $post_id * * @return string a fully qualified link to http://maps.google.com/ for this event */ public function googleMapLink( $post_id = null ) { if ( $post_id === null || ! is_numeric( $post_id ) ) { global $post; $post_id = $post->ID; } $locationMetaSuffixes = array( 'address', 'city', 'region', 'zip', 'country' ); $to_encode = ''; $url = ''; foreach ( $locationMetaSuffixes as $val ) { $metaVal = call_user_func( 'tribe_get_' . $val, $post_id ); if ( $metaVal ) { $to_encode .= $metaVal . ' '; } } if ( $to_encode ) { $url = 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' . urlencode( trim( $to_encode ) ); } return apply_filters( 'tribe_events_google_map_link', $url, $post_id ); } /** * Returns the full address of an event along with HTML markup. It * loads the full-address template to generate the HTML */ public function fullAddress( $post_id = null, $includeVenueName = false ) { global $post; if ( ! is_null( $post_id ) ) { $tmp_post = $post; $post = get_post( $post_id ); } ob_start(); tribe_get_template_part( 'modules/address' ); $address = ob_get_contents(); ob_end_clean(); if ( ! empty( $tmp_post ) ) { $post = $tmp_post; } return $address; } /** * Returns a string version of the full address of an event * * @param int|WP_Post The post object or post id. * * @return string The event's address. */ public function fullAddressString( $postId = null ) { $address = ''; if ( tribe_get_address( $postId ) ) { $address .= tribe_get_address( $postId ); } if ( tribe_get_city( $postId ) ) { if ( $address != '' ) { $address .= ', '; } $address .= tribe_get_city( $postId ); } if ( tribe_get_region( $postId ) ) { if ( $address != '' ) { $address .= ', '; } $address .= tribe_get_region( $postId ); } if ( tribe_get_zip( $postId ) ) { if ( $address != '' ) { $address .= ', '; } $address .= tribe_get_zip( $postId ); } if ( tribe_get_country( $postId ) ) { if ( $address != '' ) { $address .= ', '; } $address .= tribe_get_country( $postId ); } return $address; } /** * plugin activation callback * @see register_deactivation_hook() * * @param bool $network_deactivating */ public static function activate() { self::instance()->plugins_loaded(); self::flushRewriteRules(); if ( ! is_network_admin() && ! isset( $_GET['activate-multi'] ) ) { set_transient( '_tribe_events_activation_redirect', 1, 30 ); } } /** * plugin deactivation callback * @see register_deactivation_hook() * * @param bool $network_deactivating */ public static function deactivate( $network_deactivating ) { $deactivation = new Tribe__Events__Deactivation( $network_deactivating ); add_action( 'shutdown', array( $deactivation, 'deactivate' ) ); } /** * Converts a set of inputs to YYYY-MM-DD HH:MM:SS format for MySQL * * @param string $date The date. * @param int $hour The hour of the day. * @param int $minute The minute of the hour. * @param string $meridian "am" or "pm". * * @return string The date and time. * @todo remove - unused */ public function dateToTimeStamp( $date, $hour, $minute, $meridian ) { _deprecated_function( __METHOD__, '3.11', 'strtotime' ); if ( preg_match( '/(PM|pm)/', $meridian ) && $hour < 12 ) { $hour += '12'; } if ( preg_match( '/(AM|am)/', $meridian ) && $hour == 12 ) { $hour = '00'; } $date = $this->dateHelper( $date ); return "$date $hour:$minute:00"; } /** * Ensures date follows proper YYYY-MM-DD format * converts /, - and space chars to - * * @param string $date The date. * * @return string The cleaned-up date. * @todo remove - unused */ protected function dateHelper( $date ) { _deprecated_function( __METHOD__, '3.11', 'date' ); if ( $date == '' ) { return date( Tribe__Date_Utils::DBDATEFORMAT ); } $date = str_replace( array( '-', '/', ' ', ':', chr( 150 ), chr( 151 ), chr( 45 ) ), '-', $date ); // ensure no extra bits are added list( $year, $month, $day ) = explode( '-', $date ); if ( ! checkdate( $month, $day, $year ) ) { $date = date( Tribe__Date_Utils::DBDATEFORMAT ); } // today's date if error else { $date = $year . '-' . $month . '-' . $day; } return $date; } /** * Adds an alias for get_post_meta so we can override empty values with defaults. * If you need the raw unfiltered data, use get_post_meta directly. * This is mainly for templates. * * @param int $id The post id. * @param string $meta The meta key. * @param bool $single Return as string? Or array? * * @return mixed The meta. */ public function getEventMeta( $id, $meta, $single = true ) { $value = get_post_meta( $id, $meta, $single ); if ( $value === false ) { $method = str_replace( '_Event', '', $meta ); $default = call_user_func( array( $this->defaults(), strtolower( $method ) ) ); $value = apply_filters( 'filter_eventsDefault' . $method, $default ); } return $value; } /** * ensure only one venue or organizer is created during post preview * subsequent previews will reuse that same post * * ensure that preview post is the one that's used when the event is published, * unless we're publishing with a saved venue * * @param $post_type can be 'venue' or 'organizer' */ protected function manage_preview_metapost( $post_type, $event_id ) { if ( ! in_array( $post_type, array( 'venue', 'organizer' ) ) ) { return; } $posttype = ucfirst( $post_type ); $posttype_id = $posttype . 'ID'; $meta_key = '_preview_' . $post_type . '_id'; $valid_post_id = "tribe_get_{$post_type}_id"; $create = "create$posttype"; $preview_post_id = get_post_meta( $event_id, $meta_key, true ); $doing_preview = ($_REQUEST['wp-preview'] == 'dopreview'); if ( empty( $_POST[ $posttype ][ $posttype_id ] ) ) { // the event is set to use a new metapost if ( $doing_preview ) { // we're previewing if ( $preview_post_id && $preview_post_id == $valid_post_id( $preview_post_id ) ) { // a preview post has been created and is valid, update that wp_update_post( array( 'ID' => $preview_post_id, 'post_title' => $_POST[ $posttype ][ $posttype ], ) ); } else { // a preview post has not been created yet, or is not valid - create one and save the ID $preview_post_id = Tribe__Events__API::$create( $_POST[ $posttype ], 'draft' ); update_post_meta( $event_id, $meta_key, $preview_post_id ); } } if ( $preview_post_id ) { // set the preview post id as the event metapost id in the $_POST array // so Tribe__Events__API::saveEventVenue() doesn't make a new post $_POST[ $posttype ][ $posttype_id ] = (int) $preview_post_id; } } else { // we're using a saved metapost, discard any preview post if ( $preview_post_id ) { wp_delete_post( $preview_post_id ); global $wpdb; $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE `meta_key` = '$meta_key' AND `meta_value` = $preview_post_id" ); } } } /** * Adds / removes the event details as meta tags to the post. * * @param int $postId * @param WP_Post $post * */ public function addEventMeta( $postId, $post ) { // only continue if it's an event post if ( $post->post_type !== self::POSTTYPE || defined( 'DOING_AJAX' ) ) { return; } // don't do anything on autosave or auto-draft either or massupdates if ( wp_is_post_autosave( $postId ) || $post->post_status == 'auto-draft' || isset( $_GET['bulk_edit'] ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'inline-save' ) ) { return; } // don't do anything on other wp_insert_post calls if ( isset( $_POST['post_ID'] ) && $postId != $_POST['post_ID'] ) { return; } if ( ! isset( $_POST['ecp_nonce'] ) ) { return; } if ( ! wp_verify_nonce( $_POST['ecp_nonce'], self::POSTTYPE ) ) { return; } if ( ! current_user_can( 'edit_tribe_events' ) ) { return; } // Remove this hook to avoid an infinite loop, because saveEventMeta calls wp_update_post when the post is set to always show in calendar remove_action( 'save_post', array( $this, 'addEventMeta' ), 15 ); $_POST['Organizer'] = isset( $_POST['organizer'] ) ? stripslashes_deep( $_POST['organizer'] ) : null; $_POST['Venue'] = isset( $_POST['venue'] ) ? stripslashes_deep( $_POST['venue'] ) : null; /** * handle previewed venues and organizers */ $this->manage_preview_metapost( 'venue', $postId ); $this->manage_preview_metapost( 'organizer', $postId ); /** * When we have a VenueID/OrganizerID, we just save the ID, because we're not * editing the venue/organizer from within the event. */ $venue_pto = get_post_type_object( self::VENUE_POST_TYPE ); if ( isset( $_POST['Venue']['VenueID'] ) && ! empty( $_POST['Venue']['VenueID'] ) ) { $_POST['Venue'] = array( 'VenueID' => intval( $_POST['Venue']['VenueID'] ) ); } elseif ( empty( $venue_pto->cap->create_posts ) || ! current_user_can( $venue_pto->cap->create_posts ) ) { $_POST['Venue'] = array(); } $_POST['Organizer'] = $this->normalize_organizer_submission( $_POST['Organizer'] ); Tribe__Events__API::saveEventMeta( $postId, $_POST, $post ); // Add this hook back in add_action( 'save_post_' . self::POSTTYPE, array( $this, 'addEventMeta' ), 15, 2 ); } public function normalize_organizer_submission( $submission ) { $organizer_pto = get_post_type_object( self::ORGANIZER_POST_TYPE ); $organizers = array(); if ( ! isset( $submission['OrganizerID'] ) ) { return $organizers; // not a valid submission } if ( is_array( $submission['OrganizerID'] ) ) { foreach ( $submission['OrganizerID'] as $key => $organizer_id ) { if ( ! empty( $organizer_id ) ) { $organizers[] = array( 'OrganizerID' => intval( $organizer_id ) ); } elseif ( ! empty( $organizer_pto->cap->create_posts ) && current_user_can( $organizer_pto->cap->create_posts ) ) { $o = array(); foreach ( array( 'Organizer', 'Phone', 'Website', 'Email' ) as $field_name ) { $o[ $field_name ] = isset( $submission[ $field_name ][ $key ] ) ? $submission[ $field_name ][ $key ] : ''; } $organizers[] = $o; } } return $organizers; } // old style with single organizer fields if ( current_user_can( $organizer_pto->cap->create_posts ) ) { $o = array(); foreach ( array( 'Organizer', 'Phone', 'Website', 'Email' ) as $field_name ) { $o[ $field_name ] = isset( $submission[ $field_name ] ) ? $submission[ $field_name ] : ''; } $organizers[] = $o; $o[ $field_name ] = isset( $submission[ $field_name ] ) ? $submission[ $field_name ] : ''; } return $organizers; } /** * Intended to run when the save_post_tribe_events action is fired. * * At this point we know an event is being updated or created and, if the post is going to * be visible, we can set up a further action to handle updating our record of the * populated date range once the post meta containing the start and end date for the post * has saved. */ public function maybe_update_known_range( $post_id ) { // If the event isn't going to be visible (perhaps it's been trashed) rebuild dates and bail if ( ! in_array( get_post_status( $post_id ), array( 'publish', 'private', 'protected' ) ) ) { $this->rebuild_known_range(); return; } add_action( 'tribe_events_update_meta', array( $this, 'update_known_range' ) ); } /** * Intelligently updates our record of the earliest start date/latest event date in * the system. If the existing earliest/latest values have not been superseded by the new post's * start/end date then no update takes place. * * This is deliberately hooked into save_post, rather than save_post_tribe_events, to avoid issues * where the removal/restoration of hooks within addEventMeta() etc might stop this method from * actually being called (relates to a core WP bug). */ public function update_known_range( $object_id ) { $current_min = tribe_events_earliest_date(); $current_max = tribe_events_latest_date(); $event_start = tribe_get_start_date( $object_id, false, Tribe__Date_Utils::DBDATETIMEFORMAT ); $event_end = tribe_get_end_date( $object_id, false, Tribe__Date_Utils::DBDATETIMEFORMAT ); if ( $current_min > $event_start ) { tribe_update_option( 'earliest_date', $event_start ); } if ( $current_max < $event_end ) { tribe_update_option( 'latest_date', $event_end ); } } /** * Fires on delete_post and decides whether or not to rebuild our record or * earliest/latest event dates (which will be done when deleted_post fires, * so that the deleted event is removed from the db before we recalculate). * * @param $post_id */ public function maybe_rebuild_known_range( $post_id ) { if ( self::POSTTYPE === get_post_type( $post_id ) ) { add_action( 'deleted_post', array( $this, 'rebuild_known_range' ) ); } } /** * Determine the earliest start date and latest end date currently in the database * and store those values for future use. */ public function rebuild_known_range() { global $wpdb; remove_action( 'deleted_post', array( $this, 'rebuild_known_range' ) ); $earliest = strtotime( $wpdb->get_var( $wpdb->prepare( " SELECT MIN(meta_value) FROM $wpdb->postmeta JOIN $wpdb->posts ON post_id = ID WHERE meta_key = '_EventStartDate' AND post_type = '%s' AND post_status IN ('publish', 'private', 'protected') ", self::POSTTYPE ) ) ); $latest = strtotime( $wpdb->get_var( $wpdb->prepare( " SELECT MAX(meta_value) FROM $wpdb->postmeta JOIN $wpdb->posts ON post_id = ID WHERE meta_key = '_EventEndDate' AND post_type = '%s' AND post_status IN ('publish', 'private', 'protected') ", self::POSTTYPE ) ) ); if ( $earliest ) { tribe_update_option( 'earliest_date', date( Tribe__Date_Utils::DBDATETIMEFORMAT, $earliest ) ); } if ( $latest ) { tribe_update_option( 'latest_date', date( Tribe__Date_Utils::DBDATETIMEFORMAT, $latest ) ); } } /** * Adds the '_Origin' meta field for a newly inserted events-calendar post. * * @param int $postId , the post ID * @param WP_Post $post , the post object * */ public function addPostOrigin( $postId, $post ) { // Only continue of the post being added is an event, venue, or organizer. if ( isset( $postId ) && isset( $post->post_type ) ) { if ( $post->post_type == self::POSTTYPE ) { $post_type = '_Event'; } elseif ( $post->post_type == self::VENUE_POST_TYPE ) { $post_type = '_Venue'; } elseif ( $post->post_type == self::ORGANIZER_POST_TYPE ) { $post_type = '_Organizer'; } else { return; } //only set origin once $origin = get_post_meta( $postId, $post_type . 'Origin', true ); if ( ! $origin ) { add_post_meta( $postId, $post_type . 'Origin', apply_filters( 'tribe-post-origin', 'events-calendar', $postId, $post ) ); } } } /** * Publishes associated venue/organizer when an event is published * * @param int $postID , the post ID * @param WP_Post $post , the post object * */ public function publishAssociatedTypes( $postID, $post ) { // don't need to save the venue or organizer meta when we are just publishing remove_action( 'save_post_' . self::VENUE_POST_TYPE, array( $this, 'save_venue_data' ), 16, 2 ); remove_action( 'save_post_' . self::ORGANIZER_POST_TYPE, array( $this, 'save_organizer_data' ), 16, 2 ); // save venue and organizer info on first pass if ( isset( $post->post_status ) && $post->post_status == 'publish' ) { //get venue and organizer and publish them $pm = get_post_custom( $post->ID ); do_action( 'log', 'publishing an event with a venue', 'tribe-events', $post ); // save venue on first setup if ( ! empty( $pm['_EventVenueID'] ) ) { $venue_id = is_array( $pm['_EventVenueID'] ) ? current( $pm['_EventVenueID'] ) : $pm['_EventVenueID']; if ( $venue_id ) { do_action( 'log', 'event has a venue', 'tribe-events', $venue_id ); $venue_post = get_post( $venue_id ); if ( ! empty( $venue_post ) && $venue_post->post_status != 'publish' ) { do_action( 'log', 'venue post found', 'tribe-events', $venue_post ); $venue_post->post_status = 'publish'; wp_update_post( $venue_post ); $did_save = true; } } } // save organizer on first setup if ( ! empty( $pm['_EventOrganizerID'] ) ) { $org_id = is_array( $pm['_EventOrganizerID'] ) ? current( $pm['_EventOrganizerID'] ) : $pm['_EventOrganizerID']; if ( $org_id ) { $org_post = get_post( $org_id ); if ( ! empty( $org_post ) && $org_post->post_status != 'publish' ) { $org_post->post_status = 'publish'; wp_update_post( $org_post ); $did_save = true; } } } } // put the actions back add_action( 'save_post_' . self::VENUE_POST_TYPE, array( $this, 'save_venue_data' ), 16, 2 ); add_action( 'save_post_' . self::ORGANIZER_POST_TYPE, array( $this, 'save_organizer_data' ), 16, 2 ); } /** * Make sure the venue meta gets saved * * @param int $postID The venue id. * @param WP_Post $post The post object. * * @return null */ public function save_venue_data( $postID = null, $post = null ) { // was a venue submitted from the single venue post editor? if ( empty( $_POST['post_ID'] ) || $_POST['post_ID'] != $postID || empty( $_POST['venue'] ) ) { return; } // is the current user allowed to edit this venue? if ( ! current_user_can( 'edit_tribe_venue', $postID ) ) { return; } $data = stripslashes_deep( $_POST['venue'] ); Tribe__Events__API::updateVenue( $postID, $data ); } /** * Get venue info. * * @param int $p post id * @param $args * * @return WP_Query->posts || false */ public function get_venue_info( $p = null, $args = array() ) { $defaults = array( 'post_type' => self::VENUE_POST_TYPE, 'nopaging' => 1, 'post_status' => 'publish', 'ignore_sticky_posts ' => 1, 'orderby' => 'title', 'order' => 'ASC', 'p' => $p, ); $args = wp_parse_args( $args, $defaults ); $r = new WP_Query( $args ); if ( $r->have_posts() ) : return $r->posts; endif; return false; } /** * Make sure the organizer meta gets saved * * @param int $postID The organizer id. * @param WP_Post $post The post object. * * @return null */ public function save_organizer_data( $postID = null, $post = null ) { // was an organizer submitted from the single organizer post editor? if ( empty( $_POST['post_ID'] ) || $_POST['post_ID'] != $postID || empty( $_POST['organizer'] ) ) { return; } // is the current user allowed to edit this venue? if ( ! current_user_can( 'edit_tribe_organizer', $postID ) ) { return; } $data = stripslashes_deep( $_POST['organizer'] ); Tribe__Events__API::updateOrganizer( $postID, $data ); } /** * Add a new Organizer * * @param $data * @param null $post * * @return int|WP_Error */ public function add_new_organizer( $data, $post = null ) { if ( $data['OrganizerID'] ) { return $data['OrganizerID']; } if ( $post->post_type == self::ORGANIZER_POST_TYPE && $post->ID ) { $data['OrganizerID'] = $post->ID; } //google map checkboxes $postdata = array( 'post_title' => $data['Organizer'], 'post_type' => self::ORGANIZER_POST_TYPE, 'post_status' => 'publish', 'ID' => $data['OrganizerID'], ); if ( isset( $data['OrganizerID'] ) && $data['OrganizerID'] != '0' ) { $organizer_id = $data['OrganizerID']; wp_update_post( array( 'post_title' => $data['Organizer'], 'ID' => $data['OrganizerID'] ) ); } else { $organizer_id = wp_insert_post( $postdata, true ); } if ( ! is_wp_error( $organizer_id ) ) { foreach ( $data as $key => $var ) { update_post_meta( $organizer_id, '_Organizer' . $key, $var ); } return $organizer_id; } } /** * Get Organizer info. * * @param int $p post id * @param $args * * @return WP_Query->posts || false */ public function get_organizer_info( $p = null, $args = array() ) { $defaults = array( 'post_type' => self::ORGANIZER_POST_TYPE, 'nopaging' => 1, 'post_status' => 'publish', 'ignore_sticky_posts ' => 1, 'orderby' => 'title', 'order' => 'ASC', 'p' => $p, ); $args = wp_parse_args( $args, $defaults ); $r = new WP_Query( $args ); if ( $r->have_posts() ) : return $r->posts; endif; return false; } /** * Generates the main events settings meta box used within the event editor to configure * event dates, times and more. * * @param WP_Post $event */ public function EventsChooserBox( $event = null ) { new Tribe__Events__Admin__Event_Meta_Box( $event ); } /** * Adds a style chooser to the write post page * */ public function VenueMetaBox() { global $post; $options = ''; $style = ''; $event = $post; if ( $post->post_type == self::VENUE_POST_TYPE ) { if ( ( is_admin() && isset( $_GET['post'] ) && $_GET['post'] ) || ( ! is_admin() && isset( $event->ID ) ) ) { $saved = true; } foreach ( $this->venueTags as $tag ) { if ( $event->ID && isset( $saved ) && $saved ) { //if there is a post AND the post has been saved at least once. $$tag = esc_html( get_post_meta( $event->ID, $tag, true ) ); } else { $cleaned_tag = str_replace( '_Venue', '', $tag ); $$tag = call_user_func( array( $this->defaults(), $cleaned_tag ) ); } } } ?>
plugin_path . 'src/admin-views/venue-meta-box.php' ); if ( ! empty( $venue_meta_box_template ) ) { include( $venue_meta_box_template ); } ?>
ID; $saved = false; if ( $post->post_type == self::ORGANIZER_POST_TYPE ) { if ( ( is_admin() && isset( $_GET['post'] ) && $_GET['post'] ) || ( ! is_admin() && isset( $postId ) ) ) { $saved = true; } foreach ( $this->organizerTags as $tag ) { if ( $postId && $saved ) { //if there is a post AND the post has been saved at least once. $$tag = get_post_meta( $postId, $tag, true ); } } } ?>
plugin_path . 'src/admin-views/organizer-meta-box.php' ); if ( ! empty( $organizer_meta_box_template ) ) { include( $organizer_meta_box_template ); } ?>
verify_unique_name( $_REQUEST['name'], 'venue' ); exit; } elseif ( $_REQUEST['type'] == 'organizer' ) { echo $this->verify_unique_name( $_REQUEST['name'], 'organizer' ); exit; } } } /** * 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 (venue or organizer) * * @return boolean */ public function verify_unique_name( $name, $type ) { global $wpdb; $name = stripslashes( $name ); if ( '' == $name ) { return 1; } if ( $type == 'venue' ) { $post_type = self::VENUE_POST_TYPE; } elseif ( $type == 'organizer' ) { $post_type = self::ORGANIZER_POST_TYPE; } // 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; } /** * 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 ) { global $wpdb; $link = ''; 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 * @var boolean $anchor */ $args = (array) apply_filters( "tribe_events_get_{$mode}_event_link", $args, $post, $anchor ); $results = tribe_get_events( $args ); // If we successfully located the next/prev event, we should have precisely one element in $results if ( 1 === count( $results ) ) { $event = current( $results ); if ( ! $anchor ) { $anchor = apply_filters( 'the_title', $event->post_title ); } 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 '
'; wp_widget_rss_output( Tribe__Main::FEED_URL, array( 'items' => $items ) ); 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 ) { ?>

'in-app', 'utm_medium' => 'plugin-tec', 'utm_source' => 'post-editor', ), self::$tribeUrl . self::$addOnPath ) ) . '">', '' ); ?>

add_menu( array( 'id' => 'tribe-events', 'title' => '' . sprintf( __( '%s', 'the-events-calendar' ), $this->plural_event_label ), 'href' => $this->getLink( 'home' ), ) ); $wp_admin_bar->add_group( array( 'id' => 'tribe-events-group', 'parent' => 'tribe-events', ) ); $wp_admin_bar->add_group( array( 'id' => 'tribe-events-add-ons-group', 'parent' => 'tribe-events', ) ); $wp_admin_bar->add_group( array( 'id' => 'tribe-events-settings-group', 'parent' => 'tribe-events', ) ); if ( current_user_can( 'edit_tribe_events' ) ) { $wp_admin_bar->add_group( array( 'id' => 'tribe-events-import-group', 'parent' => 'tribe-events-add-ons-group', ) ); } $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-view-calendar', 'title' => esc_html__( 'View Calendar', 'the-events-calendar' ), 'href' => $this->getLink( 'home' ), 'parent' => 'tribe-events-group', ) ); if ( current_user_can( 'edit_tribe_events' ) ) { $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-add-event', 'title' => sprintf( esc_html__( 'Add %s', 'the-events-calendar' ), $this->singular_event_label ), 'href' => trailingslashit( get_admin_url() ) . 'post-new.php?post_type=' . self::POSTTYPE, 'parent' => 'tribe-events-group', ) ); } if ( current_user_can( 'edit_tribe_events' ) ) { $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-edit-events', 'title' => sprintf( esc_html__( 'Edit %s', 'the-events-calendar' ), $this->plural_event_label ), 'href' => trailingslashit( get_admin_url() ) . 'edit.php?post_type=' . self::POSTTYPE, 'parent' => 'tribe-events-group', ) ); } if ( current_user_can( 'publish_tribe_events' ) ) { $import_node = $wp_admin_bar->get_node( 'tribe-events-import' ); if ( ! is_object( $import_node ) ) { $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-import', 'title' => esc_html__( 'Import', 'the-events-calendar' ), 'parent' => 'tribe-events-import-group', ) ); } $wp_admin_bar->add_menu( array( 'id' => 'tribe-csv-import', 'title' => esc_html__( 'CSV', 'the-events-calendar' ), 'href' => esc_url( add_query_arg( array( 'post_type' => self::POSTTYPE, 'page' => 'events-importer', 'tab' => 'csv', ), admin_url( 'edit.php' ) ) ), 'parent' => 'tribe-events-import', ) ); } if ( current_user_can( 'manage_options' ) ) { $hide_all_settings = Tribe__Settings_Manager::get_network_option( 'allSettingsTabsHidden', '0' ); if ( $hide_all_settings == '0' ) { $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-settings', 'title' => esc_html__( 'Settings', 'the-events-calendar' ), 'href' => Tribe__Settings::instance()->get_url(), 'parent' => 'tribe-events-settings-group', ) ); } // Only show help link if it's not blocked in network admin. $hidden_settings_tabs = Tribe__Settings_Manager::get_network_option( 'hideSettingsTabs', array() ); if ( ! in_array( 'help', $hidden_settings_tabs ) ) { $wp_admin_bar->add_menu( array( 'id' => 'tribe-events-help', 'title' => esc_html__( 'Help', 'the-events-calendar' ), 'href' => Tribe__Settings::instance()->get_url( array( 'tab' => 'help' ) ), 'parent' => 'tribe-events-settings-group', ) ); } } } } /** * 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 * */ public function prepare_to_fix_tagcloud_links() { 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 * * @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 ) { if ( $taxonomy == 'post_tag' && empty( $context ) ) { $link = add_query_arg( array( 'post_type' => self::POSTTYPE ), $link ); } return esc_url( $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', ); 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 . '{common/src,src}/deprecated/*.php', GLOB_BRACE ) 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 */ public function set_meta_factory_global() { 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