1227 lines
43 KiB
PHP
1227 lines
43 KiB
PHP
<?php
|
|
|
|
/**
|
|
* The front controller of the plugin.
|
|
*
|
|
* @author Time.ly Network Inc.
|
|
* @since 2.0
|
|
*
|
|
* @package AI1EC
|
|
* @subpackage AI1EC.Controller
|
|
*/
|
|
class Ai1ec_Front_Controller {
|
|
|
|
/**
|
|
* @var Ai1ec_Registry_Object The Object registry.
|
|
*/
|
|
protected $_registry;
|
|
|
|
/**
|
|
* @var bool Whether the domain has alredy been loaded or not.
|
|
*/
|
|
protected $_domain_loaded = false;
|
|
|
|
/**
|
|
* @var string The pagebase used by Ai1ec_Href_Helper.
|
|
*/
|
|
protected $_pagebase_for_href;
|
|
|
|
/**
|
|
* @var Ai1ec_Request_Parser Instance of the request pa
|
|
*/
|
|
protected $_request;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $_default_theme;
|
|
|
|
/**
|
|
* Initializes the default theme property.
|
|
*/
|
|
public function __construct() {
|
|
// Initialize default theme.
|
|
$this->_default_theme = array(
|
|
'theme_dir' => AI1EC_DEFAULT_THEME_PATH,
|
|
'theme_root' => AI1EC_DEFAULT_THEME_ROOT,
|
|
'theme_url' => AI1EC_THEMES_URL . '/' . AI1EC_DEFAULT_THEME_NAME,
|
|
'stylesheet' => AI1EC_DEFAULT_THEME_NAME,
|
|
'legacy' => false,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Initialize the controller.
|
|
*
|
|
* @param Ai1ec_Loader $ai1ec_loader Instance of Ai1EC classes loader
|
|
*
|
|
* @return void
|
|
*/
|
|
public function initialize( $ai1ec_loader ) {
|
|
ai1ec_start();
|
|
$this->_init( $ai1ec_loader );
|
|
$this->_initialize_dispatcher();
|
|
$lessphp = $this->_registry->get( 'less.lessphp' );
|
|
$lessphp->initialize_less_variables_if_not_set();
|
|
$this->_registry->get( 'controller.shutdown' )
|
|
->register( 'ai1ec_stop' );
|
|
add_action( 'plugins_loaded', array( $this, 'register_extensions' ), 1 );
|
|
add_action( 'after_setup_theme', array( $this, 'register_themes' ), 1 );
|
|
add_action( 'init', array( $lessphp, 'invalidate_css_cache_if_requested' ) );
|
|
}
|
|
|
|
/**
|
|
* Let other objects access default theme
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_default_theme() {
|
|
return $this->_default_theme;
|
|
}
|
|
|
|
/**
|
|
* Remove unwanted menus
|
|
*/
|
|
public function admin_menu() {
|
|
remove_submenu_page(
|
|
'edit.php?post_type=ai1ec_event',
|
|
'edit-tags.php?taxonomy=events_tags&post_type=ai1ec_event'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Notify extensions and pass them instance of objects registry.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register_extensions() {
|
|
do_action( 'ai1ec_loaded', $this->_registry );
|
|
}
|
|
|
|
/**
|
|
* Notify themes and pass them instance of objects registry.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register_themes() {
|
|
do_action( 'ai1ec_after_themes_setup', $this->_registry );
|
|
}
|
|
|
|
/**
|
|
* Returns the registry object
|
|
*
|
|
* @param mixed $discard not used. Always return the registry.
|
|
*
|
|
* @return Ai1ec_Registry_Object
|
|
*/
|
|
public function return_registry( $discard ) {
|
|
return $this->_registry;
|
|
}
|
|
|
|
/**
|
|
* If WIDGET_PARAMETER is set.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
protected function is_widget() {
|
|
return isset(
|
|
$_GET[Ai1ec_Controller_Javascript_Widget::WIDGET_PARAMETER]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* If Advanced JS cache enabled.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
protected function if_js_cache_enabled() {
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
return $settings->get( 'cache_dynamic_js' );
|
|
}
|
|
|
|
/**
|
|
* If LEGACY_WIDGET_PARAMETER is set.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
protected function is_legacy_widget() {
|
|
return isset(
|
|
$_GET[Ai1ec_Controller_Javascript_Widget::LEGACY_WIDGET_PARAMETER]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Execute commands if our plugin must handle the request.
|
|
*
|
|
* @wp_hook init
|
|
*
|
|
* @return void
|
|
*/
|
|
public function route_request() {
|
|
$this->_process_request();
|
|
// get the resolver
|
|
$resolver = $this->_registry->get(
|
|
'command.resolver',
|
|
$this->_request
|
|
);
|
|
// get the command
|
|
$commands = $resolver->get_commands();
|
|
// if we have a command
|
|
if ( ! empty( $commands ) ) {
|
|
foreach( $commands as $command ) {
|
|
$result = $command->execute();
|
|
if ( $command->stop_execution() ) {
|
|
return $result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes the URL router used by our plugin.
|
|
*
|
|
* @wp_hook init
|
|
*
|
|
* @return void
|
|
*/
|
|
public function initialize_router() {
|
|
/* @var $cal_state Ai1ec_Calendar_State */
|
|
$cal_state = $this->_registry->get( 'calendar.state' );
|
|
$cal_state->set_routing_initialization( true );
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
$cal_page = $settings->get( 'calendar_page_id' );
|
|
|
|
if (
|
|
! $cal_page ||
|
|
$cal_page < 1
|
|
) { // Routing may not be affected in any way if no calendar page exists.
|
|
$cal_state->set_routing_initialization( false );
|
|
return null;
|
|
}
|
|
$router = $this->_registry->get( 'routing.router' );
|
|
$localization_helper = $this->_registry->get( 'p28n.wpml' );
|
|
$page_base = '';
|
|
$clang = '';
|
|
|
|
if ( $localization_helper->is_wpml_active() ) {
|
|
$trans = $localization_helper
|
|
->get_wpml_translations_of_page(
|
|
$cal_page,
|
|
true
|
|
);
|
|
$clang = $localization_helper->get_language();
|
|
if ( isset( $trans[$clang] ) ) {
|
|
$cal_page = $trans[$clang];
|
|
}
|
|
}
|
|
$template_link_helper = $this->_registry->get( 'template.link.helper' );
|
|
|
|
if ( ! get_post( $cal_page ) ) {
|
|
$cal_state->set_routing_initialization( false );
|
|
return null;
|
|
}
|
|
|
|
$page_base = $template_link_helper->get_page_link(
|
|
$cal_page
|
|
);
|
|
|
|
$page_base = Ai1ec_Wp_Uri_Helper::get_pagebase( $page_base );
|
|
$page_link = 'index.php?page_id=' .
|
|
$cal_page;
|
|
$pagebase_for_href = Ai1ec_Wp_Uri_Helper::get_pagebase_for_links(
|
|
get_page_link( $cal_page ),
|
|
$clang
|
|
);
|
|
|
|
// save the pagebase to set up the factory later
|
|
$application = $this->_registry->get( 'bootstrap.registry.application' );
|
|
$application->set( 'calendar_base_page', $pagebase_for_href );
|
|
$option = $this->_registry->get( 'model.option' );
|
|
|
|
// If the calendar is set as the front page, disable permalinks.
|
|
// They would not be legal under a Windows server. See:
|
|
// https://issues.apache.org/bugzilla/show_bug.cgi?id=41441
|
|
|
|
if (
|
|
$option->get( 'permalink_structure' ) &&
|
|
( int ) get_option( 'page_on_front' ) !==
|
|
( int ) $cal_page
|
|
) {
|
|
$application->set( 'permalinks_enabled', true );
|
|
}
|
|
|
|
$router->asset_base( $page_base )
|
|
->register_rewrite( $page_link );
|
|
$cal_state->set_routing_initialization( false );
|
|
}
|
|
|
|
/**
|
|
* Initialize the system.
|
|
*
|
|
* Perform all the inizialization needed for the system.
|
|
* Throws some uncatched exception for critical failures.
|
|
* Plugin will be disabled by the exception handler on those failures.
|
|
*
|
|
* @param Ai1ec_Loader $ai1ec_loader Instance of Ai1EC classes loader
|
|
*
|
|
* @throws Ai1ec_Constants_Not_Set_Exception
|
|
* @throws Ai1ec_Database_Update_Exception
|
|
* @throws Ai1ec_Database_Schema_Exception
|
|
*
|
|
* @return void Method does not return
|
|
*/
|
|
protected function _init( $ai1ec_loader ) {
|
|
$exception = null;
|
|
// Load the textdomain
|
|
add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
|
|
try {
|
|
// Initialize the registry object
|
|
$this->_initialize_registry( $ai1ec_loader );
|
|
$this->_registry->get( 'event.dispatcher' )->register_filter(
|
|
'ai1ec_perform_scheme_update',
|
|
array( 'database.datetime-migration', 'filter_scheme_update' )
|
|
);
|
|
// Procedures to take when upgrading plugin version
|
|
$this->_plugin_upgrade_procedures();
|
|
// Load the css if needed
|
|
$this->_load_css_if_needed();
|
|
// Initialize the crons
|
|
$this->_install_crons();
|
|
// Register the activation hook
|
|
$this->_initialize_schema();
|
|
// set the default theme if not set
|
|
$this->_add_default_theme_if_not_set();
|
|
} catch ( Ai1ec_Constants_Not_Set_Exception $e ) {
|
|
// This is blocking, throw it and disable the plugin
|
|
$exception = $e;
|
|
} catch ( Ai1ec_Database_Update_Exception $e ) {
|
|
// Blocking throw it so that the plugin is disabled
|
|
$exception = $e;
|
|
} catch ( Ai1ec_Database_Schema_Exception $e ) {
|
|
// Blocking throw it so that the plugin is disabled
|
|
$exception = $e;
|
|
} catch ( Ai1ec_Scheduling_Exception $e ) {
|
|
// not blocking
|
|
}
|
|
|
|
if ( null !== $exception ) {
|
|
throw $exception;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the default theme if no theme is set, or populate theme info array if
|
|
* insufficient information is currently being stored.
|
|
*
|
|
* @uses apply_filters() Calls 'ai1ec_pre_save_current_theme' hook to allow
|
|
* overwriting of theme information before being stored.
|
|
*/
|
|
protected function _add_default_theme_if_not_set() {
|
|
$option = $this->_registry->get( 'model.option' );
|
|
$theme = $option->get( 'ai1ec_current_theme', array() );
|
|
$update = false;
|
|
// Theme setting is undefined; default to Vortex.
|
|
if ( empty( $theme ) ) {
|
|
$theme = $this->_default_theme;
|
|
$update = true;
|
|
}
|
|
// Legacy settings; in 1.x the active theme was stored as a bare string,
|
|
// and they were located in a different folder than they are now.
|
|
else if ( is_string( $theme ) ) {
|
|
$theme_name = strtolower( $theme );
|
|
$core_themes = explode( ',', AI1EC_CORE_THEMES );
|
|
$legacy = ! in_array( $theme_name, $core_themes );
|
|
|
|
if ( $legacy ) {
|
|
$root = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . AI1EC_THEME_FOLDER;
|
|
$url = WP_CONTENT_URL . '/' . AI1EC_THEME_FOLDER . '/' . $theme_name;
|
|
} else {
|
|
$root = AI1EC_DEFAULT_THEME_ROOT;
|
|
$url = AI1EC_THEMES_URL . '/' . $theme_name;
|
|
}
|
|
// if it's from 1.x, move folders to avoid confusion
|
|
if ( apply_filters( 'ai1ec_move_themes_to_backup', true ) ) {
|
|
$this->_registry->get( 'theme.search' )
|
|
->move_themes_to_backup( $core_themes );
|
|
}
|
|
// Ensure existence of theme directory.
|
|
if ( ! is_dir( $root . DIRECTORY_SEPARATOR . $theme_name ) ) {
|
|
// It's missing; something is wrong with this theme. Reset theme to
|
|
// Vortex and warn the user accordingly.
|
|
$option->set( 'ai1ec_current_theme', $this->_default_theme );
|
|
$notification = $this->_registry->get( 'notification.admin' );
|
|
$notification->store(
|
|
sprintf(
|
|
Ai1ec_I18n::__(
|
|
'Your active calendar theme could not be properly initialized. The default theme has been activated instead. Please visit %s and try reactivating your theme manually.'
|
|
),
|
|
'<a href="' . ai1ec_admin_url( AI1EC_THEME_SELECTION_BASE_URL ) . '">' .
|
|
Ai1ec_I18n::__( 'Calendar Themes' ) . '</a>'
|
|
),
|
|
'error',
|
|
1
|
|
);
|
|
}
|
|
|
|
$theme = array(
|
|
'theme_dir' => $root . DIRECTORY_SEPARATOR . $theme_name,
|
|
'theme_root' => $root,
|
|
'theme_url' => $url,
|
|
'stylesheet' => $theme_name,
|
|
'legacy' => $legacy,
|
|
);
|
|
$update = true;
|
|
}
|
|
// Ensure 'theme_url' is defined, as this property was added after the first
|
|
// public beta release.
|
|
else if ( ! isset( $theme['theme_url'] ) ) {
|
|
if ( $theme['legacy'] ) {
|
|
$theme['theme_url'] = WP_CONTENT_URL . '/' . AI1EC_THEME_FOLDER . '/' .
|
|
$theme['stylesheet'];
|
|
} else {
|
|
$theme['theme_url'] = AI1EC_THEMES_URL . '/' . $theme['stylesheet'];
|
|
}
|
|
$update = true;
|
|
}
|
|
|
|
if ( $update ) {
|
|
$theme = apply_filters( 'ai1ec_pre_save_current_theme', $theme );
|
|
$option->set( 'ai1ec_current_theme', $theme );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds actions handled by the front controller.
|
|
*/
|
|
protected function _add_front_controller_actions() {
|
|
// Initialize router. I use add_action as the dispatcher would just add
|
|
// overhead.
|
|
add_action(
|
|
'init',
|
|
array( $this, 'initialize_router' ),
|
|
PHP_INT_MAX - 1
|
|
);
|
|
add_action(
|
|
'widgets_init',
|
|
array( 'Ai1ec_View_Admin_Widget', 'register_widget' )
|
|
);
|
|
|
|
if (
|
|
$this->is_widget() ||
|
|
$this->is_legacy_widget()
|
|
) {
|
|
$this->_registry->get( 'event.dispatcher' )->register_action(
|
|
'init',
|
|
array( 'controller.javascript-widget', 'render_js_widget' ),
|
|
PHP_INT_MAX
|
|
);
|
|
}
|
|
|
|
// Route the request.
|
|
$action = 'template_redirect';
|
|
if ( is_admin() ) {
|
|
$action = 'init';
|
|
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
|
}
|
|
add_action( $action, array( $this, 'route_request' ) );
|
|
add_filter( 'ai1ec_registry', array( $this, 'return_registry' ) );
|
|
}
|
|
|
|
/**
|
|
* Initialize the dispatcher.
|
|
*
|
|
* Complete this when writing the dispatcher.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function _initialize_dispatcher() {
|
|
$dispatcher = $this->_registry->get( 'event.dispatcher' );
|
|
$dispatcher->register_action(
|
|
'init',
|
|
array( 'post.custom-type', 'register' )
|
|
);
|
|
$this->_add_front_controller_actions();
|
|
if ( isset( $_GET[Ai1ec_Javascript_Controller::LOAD_JS_PARAMETER] ) ) {
|
|
$dispatcher->register_action(
|
|
'wp_loaded',
|
|
array( 'controller.javascript', 'render_js' )
|
|
);
|
|
}
|
|
$dispatcher->register_action(
|
|
'before_delete_post',
|
|
array( 'model.event.trashing', 'before_delete_post' ),
|
|
0,
|
|
3
|
|
);
|
|
$dispatcher->register_action(
|
|
'delete_post',
|
|
array( 'model.event.trashing', 'delete' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_trash_post',
|
|
array( 'model.event.trashing', 'trash_post' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'trashed_post',
|
|
array( 'model.event.trashing', 'trashed_post' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'untrash_post',
|
|
array( 'model.event.trashing', 'untrash_post' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'untrashed_post',
|
|
array( 'model.event.trashing', 'untrashed_post' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'pre_http_request',
|
|
array( 'http.request', 'pre_http_request' ),
|
|
10,
|
|
3
|
|
);
|
|
$dispatcher->register_action(
|
|
'http_request_args',
|
|
array( 'http.request', 'init_certificate' ),
|
|
10,
|
|
2
|
|
);
|
|
// add the filter to let the organize page work
|
|
$dispatcher->register_action(
|
|
'admin_init',
|
|
array( 'view.admin.organize', 'add_taxonomy_actions' ),
|
|
10000
|
|
);
|
|
$dispatcher->register_action(
|
|
'plugins_loaded',
|
|
array( 'theme.loader', 'clean_cache_on_upgrade' ),
|
|
PHP_INT_MAX
|
|
);
|
|
$dispatcher->register_filter(
|
|
'get_the_excerpt',
|
|
array( 'view.event.content', 'event_excerpt' ),
|
|
11
|
|
);
|
|
remove_filter( 'the_excerpt', 'wpautop', 10 );
|
|
$dispatcher->register_filter(
|
|
'the_excerpt',
|
|
array( 'view.event.content', 'event_excerpt_noautop' ),
|
|
11
|
|
);
|
|
$dispatcher->register_filter(
|
|
'robots_txt',
|
|
array( 'robots.helper', 'rules' ),
|
|
10,
|
|
2
|
|
);
|
|
$dispatcher->register_filter(
|
|
'ai1ec_dbi_debug',
|
|
array( 'http.request', 'debug_filter' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'ai1ec_dbi_debug',
|
|
array( 'compatibility.cli', 'disable_db_debug' )
|
|
);
|
|
// editing a child instance
|
|
if ( isset( $_SERVER['SCRIPT_NAME'] ) && basename( $_SERVER['SCRIPT_NAME'] ) === 'post.php' ) {
|
|
$dispatcher->register_action(
|
|
'admin_action_editpost',
|
|
array( 'model.event.parent', 'admin_init_post' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'user_has_cap',
|
|
array( 'content.filter', 'display_trash_link' ),
|
|
10,
|
|
2
|
|
);
|
|
}
|
|
// post row action for parent/child
|
|
$dispatcher->register_action(
|
|
'post_row_actions',
|
|
array( 'model.event.parent', 'post_row_actions' ),
|
|
100,
|
|
2
|
|
);
|
|
// Category colors
|
|
$dispatcher->register_action(
|
|
'events_categories_add_form_fields',
|
|
array( 'view.admin.event-category', 'events_categories_add_form_fields' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'events_categories_edit_form_fields',
|
|
array( 'view.admin.event-category', 'events_categories_edit_form_fields' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'created_events_categories',
|
|
array( 'view.admin.event-category', 'created_events_categories' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'edited_events_categories',
|
|
array( 'view.admin.event-category', 'edited_events_categories' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'manage_edit-events_categories_columns',
|
|
array( 'view.admin.event-category', 'manage_event_categories_columns' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'manage_events_categories_custom_column',
|
|
array( 'view.admin.event-category', 'manage_events_categories_custom_column' ),
|
|
10,
|
|
3
|
|
);
|
|
|
|
// register ICS cron action
|
|
$dispatcher->register_action(
|
|
Ai1ecIcsConnectorPlugin::HOOK_NAME,
|
|
array( 'calendar-feed.ics', 'cron' )
|
|
);
|
|
$dispatcher->register_shortcode(
|
|
'ai1ec',
|
|
array( 'view.calendar.shortcode', 'shortcode' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'updated_option',
|
|
array( 'model.settings', 'wp_options_observer' ),
|
|
PHP_INT_MAX - 1,
|
|
3
|
|
);
|
|
|
|
$dispatcher->register_action(
|
|
'ai1ec_settings_updated',
|
|
array( 'compatibility.check', 'ai1ec_settings_observer' ),
|
|
PHP_INT_MAX - 1,
|
|
2
|
|
);
|
|
if ( $this->if_js_cache_enabled() ) {
|
|
$dispatcher->register_action(
|
|
'ai1ec_settings_updated',
|
|
array( 'controller.javascript', 'revalidate_cache' ),
|
|
PHP_INT_MAX - 1
|
|
);
|
|
$dispatcher->register_action(
|
|
'ai1ec_settings_updated',
|
|
array( 'controller.javascript-widget', 'revalidate_cache' ),
|
|
PHP_INT_MAX - 1
|
|
);
|
|
}
|
|
|
|
if ( is_admin() ) {
|
|
// Import suggested event
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_import_suggested_event',
|
|
array( 'calendar-feed.ics', 'add_discover_events_feed_subscription' )
|
|
);
|
|
// Remove suggested event
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_remove_suggested_event',
|
|
array( 'calendar-feed.ics', 'delete_individual_event_subscription' )
|
|
);
|
|
// Search for events
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_search_events',
|
|
array( 'calendar-feed.suggested', 'search_events' )
|
|
);
|
|
// get the repeat box
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_get_repeat_box',
|
|
array( 'view.admin.get-repeat-box', 'get_repeat_box' )
|
|
);
|
|
// get the tax options box
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_get_tax_box',
|
|
array( 'view.admin.get-tax-box', 'get_tax_box' )
|
|
);
|
|
// add dismissable notice handler
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_dismiss_notice',
|
|
array( 'notification.admin', 'dismiss_notice' )
|
|
);
|
|
// save rrurle and convert it to text
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_rrule_to_text',
|
|
array( 'view.admin.get-repeat-box', 'convert_rrule_to_text' )
|
|
);
|
|
// display ticketing details in the events list
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_show_ticket_details',
|
|
array( 'view.admin.all-events', 'show_ticket_details' )
|
|
);
|
|
// display attendees list
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_show_attendees',
|
|
array( 'view.admin.all-events', 'show_attendees' )
|
|
);
|
|
// CSS and templates for ticketing options
|
|
$dispatcher->register_action(
|
|
'restrict_manage_posts',
|
|
array( 'view.admin.all-events', 'add_ticketing_styling' )
|
|
);
|
|
// taxonomy filter
|
|
$dispatcher->register_action(
|
|
'restrict_manage_posts',
|
|
array( 'view.admin.all-events', 'taxonomy_filter_restrict_manage_posts' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'parse_query',
|
|
array( 'view.admin.all-events', 'taxonomy_filter_post_type_request' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.calendar-feeds', 'add_page' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'current_screen',
|
|
array( 'view.admin.calendar-feeds', 'add_meta_box' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.add-ons', 'add_page' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.theme-switching', 'add_page' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.theme-options', 'add_page' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'current_screen',
|
|
array( 'view.admin.theme-options', 'add_meta_box' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.settings', 'add_page' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'current_screen',
|
|
array( 'view.admin.settings', 'add_meta_box' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'init',
|
|
array( 'controller.javascript', 'load_admin_js' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.samples', 'add_page' ),
|
|
100,
|
|
1
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_add_ics',
|
|
array( 'calendar-feed.ics', 'add_ics_feed' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_delete_ics',
|
|
array( 'calendar-feed.ics', 'delete_feeds_and_events' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_update_ics',
|
|
array( 'calendar-feed.ics', 'update_ics_feed' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_feeds_page_post',
|
|
array( 'calendar-feed.ics', 'handle_feeds_page_post' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_send_feedback_message',
|
|
array( 'model.review', 'send_feedback_message' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_save_feedback_review',
|
|
array( 'model.review', 'save_feedback_review' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'network_admin_notices',
|
|
array( 'notification.admin', 'send' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_notices',
|
|
array( 'notification.admin', 'send' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_footer-edit.php',
|
|
array( 'clone.renderer-helper', 'duplicate_custom_bulk_admin_footer' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'post_row_actions',
|
|
array( 'clone.renderer-helper', 'ai1ec_duplicate_post_make_duplicate_link_row' ),
|
|
100,
|
|
2
|
|
);
|
|
$dispatcher->register_action(
|
|
'add_meta_boxes',
|
|
array( 'view.admin.add-new-event', 'event_meta_box_container' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'edit_form_after_title',
|
|
array( 'view.admin.add-new-event', 'event_inline_alert' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'save_post',
|
|
array( 'model.event.creating', 'save_post' ),
|
|
10,
|
|
3
|
|
);
|
|
$dispatcher->register_action(
|
|
'pre_post_update',
|
|
array( 'model.event.creating', 'pre_post_update' ),
|
|
0,
|
|
2
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_insert_post_data',
|
|
array( 'model.event.creating', 'wp_insert_post_data' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'manage_ai1ec_event_posts_custom_column',
|
|
array( 'view.admin.all-events', 'custom_columns' ),
|
|
10,
|
|
2
|
|
);
|
|
$dispatcher->register_filter(
|
|
'manage_ai1ec_event_posts_columns',
|
|
array( 'view.admin.all-events', 'change_columns' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'manage_edit-ai1ec_event_sortable_columns',
|
|
array( 'view.admin.all-events', 'sortable_columns' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'posts_orderby',
|
|
array( 'view.admin.all-events', 'orderby' ),
|
|
10,
|
|
2
|
|
);
|
|
$dispatcher->register_filter(
|
|
'ai1ec_count_future_events',
|
|
array( 'view.admin.all-events', 'count_future_events' ),
|
|
10,
|
|
1
|
|
);
|
|
$dispatcher->register_filter(
|
|
'post_updated_messages',
|
|
array( 'view.event.post', 'post_updated_messages' )
|
|
);
|
|
add_action( 'admin_head', array( $this, 'admin_head' ) );
|
|
$dispatcher->register_action(
|
|
'plugin_action_links_' . AI1EC_PLUGIN_BASENAME,
|
|
array( 'view.admin.nav', 'plugin_action_links' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_ajax_ai1ec_rescan_cache',
|
|
array( 'twig.cache', 'rescan' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_init',
|
|
array( 'environment.check', 'run_checks' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'activated_plugin',
|
|
array( 'environment.check', 'check_addons_activation' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'upgrader_post_install',
|
|
array( 'environment.check', 'check_bulk_addons_activation' )
|
|
);
|
|
if ( $this->if_js_cache_enabled() ) {
|
|
$dispatcher->register_action(
|
|
'activated_plugin',
|
|
array( 'controller.javascript', 'revalidate_cache' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'deactivated_plugin',
|
|
array( 'controller.javascript', 'revalidate_cache' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'upgrader_post_install',
|
|
array( 'controller.javascript', 'revalidate_cache' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'activated_plugin',
|
|
array( 'controller.javascript-widget', 'revalidate_cache' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'deactivated_plugin',
|
|
array( 'controller.javascript-widget', 'revalidate_cache' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'upgrader_post_install',
|
|
array( 'controller.javascript-widget', 'revalidate_cache' )
|
|
);
|
|
|
|
}
|
|
// Widget Creator
|
|
$dispatcher->register_action(
|
|
'admin_enqueue_scripts',
|
|
array( 'css.admin', 'admin_enqueue_scripts' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'current_screen',
|
|
array( 'view.admin.widget-creator', 'add_meta_box' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.widget-creator', 'add_page' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'pre_set_site_transient_update_plugins',
|
|
array( 'calendar.updates', 'check_updates' )
|
|
);
|
|
$dispatcher->register_filter(
|
|
'plugins_api',
|
|
array( 'calendar.updates', 'plugins_api_filter' ),
|
|
10,
|
|
3
|
|
);
|
|
$dispatcher->register_action(
|
|
'admin_menu',
|
|
array( 'view.admin.tickets', 'add_page' )
|
|
);
|
|
|
|
} else { // ! is_admin()
|
|
$dispatcher->register_action(
|
|
'after_setup_theme',
|
|
array( 'theme.loader', 'execute_theme_functions' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'the_post',
|
|
array( 'post.content', 'check_content' ),
|
|
PHP_INT_MAX
|
|
);
|
|
$dispatcher->register_action(
|
|
'send_headers',
|
|
array( 'request.redirect', 'handle_categories_and_tags' )
|
|
);
|
|
$dispatcher->register_action(
|
|
'wp_head',
|
|
array( 'view.event.single', 'add_meta_tags' )
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Outputs menu icon between head tags
|
|
*/
|
|
public function admin_head() {
|
|
global $wp_version;
|
|
$argv = array(
|
|
'before_font_icons' => version_compare( $wp_version, '3.8', '<' ),
|
|
'admin_theme_img_url' => AI1EC_ADMIN_THEME_IMG_URL,
|
|
'admin_theme_font_url' => AI1EC_ADMIN_THEME_FONT_URL,
|
|
);
|
|
$this->_registry->get( 'theme.loader' )
|
|
->get_file( 'timely-menu-icon.twig', $argv, true )
|
|
->render();
|
|
}
|
|
|
|
/**
|
|
* _add_defaults method
|
|
*
|
|
* Add (merge) default options to given query variable.
|
|
*
|
|
* @param string settingsquery variable to ammend
|
|
*
|
|
* @return string|NULL Modified variable values or NULL on failure
|
|
*
|
|
* @global Ai1ec_Settings $ai1ec_settings Instance of settings object
|
|
* to pull data from
|
|
* @staticvar array $mapper Mapping of query names to
|
|
* default in settings
|
|
*/
|
|
protected function _add_defaults( $name ) {
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
static $mapper = array(
|
|
'cat' => 'categories',
|
|
'tag' => 'tags',
|
|
);
|
|
$rq_name = 'ai1ec_' . $name . '_ids';
|
|
if (
|
|
! isset( $mapper[$name] ) ||
|
|
! array_key_exists( $rq_name, $this->_request )
|
|
) {
|
|
return NULL;
|
|
}
|
|
$options = explode( ',', $this->_request[$rq_name] );
|
|
$property = 'default_' . $mapper[$name];
|
|
$options = array_merge(
|
|
$options,
|
|
$settings->get( $property )
|
|
);
|
|
$filtered = array();
|
|
foreach ( $options as $item ) { // avoid array_filter + is_numeric
|
|
$item = (int)$item;
|
|
if ( $item > 0 ) {
|
|
$filtered[] = $item;
|
|
}
|
|
}
|
|
unset( $options );
|
|
if ( empty( $filtered ) ) {
|
|
return NULL;
|
|
}
|
|
return implode( ',', $filtered );
|
|
}
|
|
|
|
/**
|
|
* Process_request function.
|
|
*
|
|
* Initialize/validate custom request array, based on contents of $_REQUEST,
|
|
* to keep track of this component's request variables.
|
|
*
|
|
* @return void
|
|
**/
|
|
protected function _process_request() {
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
$this->_request = $this->_registry->get( 'http.request.parser' );
|
|
$aco = $this->_registry->get( 'acl.aco' );
|
|
$page_id = $settings->get( 'calendar_page_id' );
|
|
if (
|
|
! $aco->is_admin() &&
|
|
$page_id &&
|
|
is_page( $page_id )
|
|
) {
|
|
foreach ( array( 'cat', 'tag' ) as $name ) {
|
|
$implosion = $this->_add_defaults( $name );
|
|
if ( $implosion ) {
|
|
$this->request['ai1ec_' . $name . '_ids'] = $implosion;
|
|
$_REQUEST['ai1ec_' . $name . '_ids'] = $implosion;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize cron functions.
|
|
*
|
|
* @throws Ai1ec_Scheduling_Exception
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function _install_crons() {
|
|
$scheduling = $this->_registry->get( 'scheduling.utility' );
|
|
$hook_name = 'ai1ec_n_cron';
|
|
$scheduling->delete( $hook_name );
|
|
}
|
|
|
|
/**
|
|
* Initialize the registry object.
|
|
*
|
|
* @param Ai1ec_Loader $ai1ec_loader Instance of Ai1EC classes loader
|
|
*
|
|
* @return void Method does not return
|
|
*/
|
|
protected function _initialize_registry( $ai1ec_loader ) {
|
|
global $ai1ec_registry;
|
|
$this->_registry = new Ai1ec_Registry_Object( $ai1ec_loader );
|
|
Ai1ec_Time_Utility::set_registry( $this->_registry );
|
|
$ai1ec_registry = $this->_registry;
|
|
}
|
|
|
|
/**
|
|
* Loads the CSS for the plugin
|
|
*
|
|
*/
|
|
protected function _load_css_if_needed() {
|
|
// ==================================
|
|
// = Add the hook to render the css =
|
|
// ==================================
|
|
if ( isset( $_GET[Ai1ec_Css_Frontend::QUERY_STRING_PARAM] ) ) {
|
|
// we need to wait for the extension to be registered if the css
|
|
// needs to be compiled. Will find a better way when compiling css.
|
|
$css_controller = $this->_registry->get( 'css.frontend' );
|
|
add_action( 'plugins_loaded', array( $css_controller, 'render_css' ), 2 );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load the texdomain for the plugin.
|
|
*
|
|
* @wp_hook plugins_loaded
|
|
*
|
|
* @return void
|
|
*/
|
|
public function load_textdomain() {
|
|
if ( false === $this->_domain_loaded ) {
|
|
load_plugin_textdomain(
|
|
AI1EC_PLUGIN_NAME, false, AI1EC_LANGUAGE_PATH
|
|
);
|
|
$this->_domain_loaded = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the schema is up to date.
|
|
*
|
|
* @throws Ai1ec_Database_Schema_Exception
|
|
* @throws Ai1ec_Database_Update_Exception
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function _initialize_schema() {
|
|
$option = $this->_registry->get( 'model.option' );
|
|
$schema_sql = $this->get_current_db_schema();
|
|
$version = sha1( $schema_sql );
|
|
// If existing DB version is not consistent with current plugin's version,
|
|
// or does not exist, then create/update table structure using dbDelta().
|
|
if ( $option->get( 'ai1ec_db_version' ) != $version ) {
|
|
|
|
$errors = $this->_registry->get( 'database.applicator' )
|
|
->check_db_consistency_for_date_migration() ;
|
|
if ( ! empty( $errors ) ) {
|
|
$message = Ai1ec_I18n::__(
|
|
'Your database is found to be corrupt. Likely previous update has failed. Please restore All-in-One Event Calendar tables from a backup and retry.<br>Following errors were found:<br>%s'
|
|
);
|
|
$message = sprintf( $message, implode( $errors, '<br>' ) );
|
|
throw new Ai1ec_Database_Update_Exception( $message );
|
|
}
|
|
$this->_registry->get( 'database.applicator' )
|
|
->remove_instance_duplicates();
|
|
|
|
if (
|
|
apply_filters( 'ai1ec_perform_scheme_update', true ) &&
|
|
$this->_registry->get( 'database.helper' )->apply_delta(
|
|
$schema_sql
|
|
)
|
|
) {
|
|
$option->set( 'ai1ec_db_version', $version );
|
|
} else {
|
|
throw new Ai1ec_Database_Update_Exception();
|
|
}
|
|
|
|
// If the schema structure upgrade is complete move contents
|
|
$categories_key = 'ai1ec_category_meta_ported';
|
|
if ( ! $option->get( $categories_key ) ) {
|
|
$this->_migrate_categories_meta();
|
|
$option->set( $categories_key, true );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Transform categories meta information.
|
|
*
|
|
* Use new `meta` table instead of legacy `colors` table.
|
|
*
|
|
* @return void Method does not return.
|
|
*/
|
|
protected function _migrate_categories_meta() {
|
|
$db = $this->_registry->get( 'dbi.dbi' );
|
|
$table_name = $db->get_table_name( 'ai1ec_event_category_colors' );
|
|
$db_h = $this->_registry->get( 'database.helper' );
|
|
if ( $db_h->table_exists( $table_name ) ) { // if old table exists otherwise ignore it
|
|
// Migrate color information
|
|
$dest_table = $db->get_table_name( 'ai1ec_event_category_meta' );
|
|
$colors = $db->select(
|
|
$table_name,
|
|
array( 'term_id', 'term_color'),
|
|
ARRAY_A
|
|
);
|
|
if ( ! empty( $colors ) ) {
|
|
foreach ( $colors as $color ) {
|
|
$db->insert( $dest_table, $color );
|
|
}
|
|
}
|
|
// Drop the old table
|
|
$db->query( 'DROP TABLE IF EXISTS ' . $table_name );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Procedures to take when upgrading plugin version
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function _plugin_upgrade_procedures() {
|
|
$option = $this->_registry->get( 'model.option' );
|
|
$version = AI1EC_VERSION;
|
|
|
|
if ( $option->get( 'ai1ec_version' ) != $version ) {
|
|
try {
|
|
// Force regeneration of JS cache
|
|
$this->_registry->get( 'controller.javascript' )->revalidate_cache();
|
|
$this->_registry->get( 'controller.javascript-widget' )->revalidate_cache();
|
|
|
|
// Run upgrade commands
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
$settings->perform_upgrade_actions();
|
|
} catch ( Exception $e ) {
|
|
}
|
|
|
|
// Update plugin version
|
|
$option->set( 'ai1ec_version', $version );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current database schema as a multi SQL statement.
|
|
*
|
|
* @return string Multiline SQL statement.
|
|
*/
|
|
public function get_current_db_schema() {
|
|
$dbi = $this->_registry->get( 'dbi.dbi' );
|
|
// =======================
|
|
// = Create table events =
|
|
// =======================
|
|
$table_name = $dbi->get_table_name( 'ai1ec_events' );
|
|
$sql = "CREATE TABLE $table_name (
|
|
post_id bigint(20) NOT NULL,
|
|
start int(10) UNSIGNED NOT NULL,
|
|
end int(10) UNSIGNED,
|
|
timezone_name varchar(50),
|
|
allday tinyint(1) NOT NULL,
|
|
instant_event tinyint(1) NOT NULL DEFAULT 0,
|
|
recurrence_rules longtext,
|
|
exception_rules longtext,
|
|
recurrence_dates longtext,
|
|
exception_dates longtext,
|
|
venue varchar(255),
|
|
country varchar(255),
|
|
address varchar(255),
|
|
city varchar(255),
|
|
province varchar(255),
|
|
postal_code varchar(32),
|
|
show_map tinyint(1),
|
|
contact_name varchar(255),
|
|
contact_phone varchar(32),
|
|
contact_email varchar(128),
|
|
contact_url varchar(255),
|
|
cost varchar(255),
|
|
ticket_url varchar(255),
|
|
ical_feed_url varchar(255),
|
|
ical_source_url varchar(255),
|
|
ical_organizer varchar(255),
|
|
ical_contact varchar(255),
|
|
ical_uid varchar(255),
|
|
show_coordinates tinyint(1),
|
|
latitude decimal(20,15),
|
|
longitude decimal(20,15),
|
|
force_regenerate tinyint(1) NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (post_id),
|
|
KEY feed_source (ical_feed_url)
|
|
) CHARACTER SET utf8;";
|
|
|
|
// ==========================
|
|
// = Create table instances =
|
|
// ==========================
|
|
$table_name = $dbi->get_table_name( 'ai1ec_event_instances' );
|
|
$sql .= "CREATE TABLE $table_name (
|
|
id bigint(20) NOT NULL AUTO_INCREMENT,
|
|
post_id bigint(20) NOT NULL,
|
|
start int(10) UNSIGNED NOT NULL,
|
|
end int(10) UNSIGNED NOT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY evt_instance (post_id,start)
|
|
) CHARACTER SET utf8;";
|
|
|
|
// ================================
|
|
// = Create table category colors =
|
|
// ================================
|
|
$table_name = $dbi->get_table_name( 'ai1ec_event_category_meta' );
|
|
$sql .= "CREATE TABLE $table_name (
|
|
term_id bigint(20) NOT NULL,
|
|
term_color varchar(255) NOT NULL,
|
|
term_image varchar(254) NULL DEFAULT NULL,
|
|
PRIMARY KEY (term_id)
|
|
) CHARACTER SET utf8;";
|
|
|
|
return $sql;
|
|
}
|
|
}
|