child_file = __FILE__; // Set child file.
$this->define_constants(); // Define plugin constants.
$this->includes(); // Include files.
$this->init_hooks(); // Initialize hooks.
$this->load_events(); // Load events.
}
/**
* Absolute URL to plugin directory WITHOUT final slash.
*
* @since 1.4.0
* @return string
*/
public function get_base_url() {
return plugins_url( '', __FILE__ );
}
/**
* Full path to plugin directory WITH final slash.
*
* @since 1.4.0
* @return string
*/
public function get_base_dir() {
return plugin_dir_path( __FILE__ );
}
/**
* Plugin directory name.
*
* @since 1.4.0
* @return string
*/
public function get_base_name() {
return plugin_basename( __FILE__ );
}
/**
* Include Files.
*
* @since 1.1
*/
public function includes() {
$composer_autoloader_file = __DIR__ . '/vendor/autoload.php';
if ( file_exists( $composer_autoloader_file ) ) {
require_once $composer_autoloader_file;
}
require_once MWPAL_BASE_DIR . 'includes/helpers/class-datahelper.php';
require_once MWPAL_BASE_DIR . 'includes/models/class-activerecord.php';
require_once MWPAL_BASE_DIR . 'includes/models/class-query.php';
require_once MWPAL_BASE_DIR . 'includes/models/class-occurrencequery.php';
require_once MWPAL_BASE_DIR . 'includes/views/class-auditlogview.php';
require_once MWPAL_BASE_DIR . 'includes/vendors/autoload.php';
// Autoload files.
\WSAL\MainWPExtension\Autoload\mwpal_autoload( MWPAL_BASE_DIR . 'includes' );
}
/**
* Initialize Plugin Hooks.
*
* @since 1.1
*/
public function init_hooks() {
register_activation_hook( __FILE__, array( $this, 'install_extension' ) ); // Installation routine.
add_action( 'init', array( $this, 'mwpal_init' ) ); // Start listening to events.
add_action( 'init', array( $this, 'load_mwpal_text_domain' ) );
add_action( 'mwp_events_cleanup', array( $this, 'events_cleanup' ) ); // Schedule hook for refreshing events.
add_filter( 'mainwp_getextensions', array( &$this, 'get_this_extension' ) );
add_action( 'admin_init', array( &$this, 'redirect_on_activate' ) );
add_filter( 'plugin_action_links_' . MWPAL_BASE_NAME, array( $this, 'add_plugin_page_links' ), 20, 1 );
add_action( 'plugins_loaded', array( $this, 'load_mwpal_extension' ) );
add_action( 'admin_notices', array( &$this, 'mainwp_error_notice' ) );
add_action( 'mainwp_delete_site', array( $this, 'remove_almwp_child_when_removed_from_mwp' ), 10, 1 );
add_action( 'mainwp_added_new_site', array( $this, 'add_almwp_child_when_added_to_mwp' ), 10, 1 );
add_action( 'mainwp_header_left', array( $this, 'custom_page_title' ) );
add_action( 'admin_notices', array( &$this, 'mainwp_merged_notice' ) );
// This filter will return true if the main plugin is activated.
$this->mainwp_main_activated = apply_filters( 'mainwp_activated_check', false );
if ( false !== $this->mainwp_main_activated ) {
$this->activate_this_plugin();
} else {
// Because sometimes our main plugin is activated after the extension plugin is activated we also have a second step,
// listening to the 'mainwp_activated' action. This action is triggered by MainWP after initialisation.
add_action( 'mainwp_activated', array( &$this, 'activate_this_plugin' ) );
}
// Include formerly premium extensions.
require_once MWPAL_BASE_DIR . 'extensions/class-extensions.php';
}
/**
* @return Settings
* @since 1.7.0
*/
public function settings() {
if ( $this->settings instanceof Settings ) {
return $this->settings;
}
$this->settings = new \WSAL\MainWPExtension\Settings();
return $this->settings;
}
/**
* Start listening to events.
*/
public function mwpal_init() {
// Initalize the classes.
$this->settings = new \WSAL\MainWPExtension\Settings();
$this->constants = new \WSAL\MainWPExtension\ConstantManager();
$this->alerts = new \WSAL\MainWPExtension\AlertManager();
$this->sensor_mainwp = new \WSAL\MainWPExtension\Sensors\Sensor_MainWP();
$this->extension_view = new \WSAL\MainWPExtension\Views\View();
if ( false === $this->settings->get_option( 'setup-complete' ) ) {
new \WSAL\MainWPExtension\Views\Setup_Wizard( $this );
}
// Hook extension events.
$this->sensor_mainwp->hook_events();
// Activity log extension initialized.
do_action( 'mwpal_init' );
}
/**
* Load our text domain.
*/
public function load_mwpal_text_domain() {
$locale = apply_filters( 'plugin_locale', get_locale(), 'mwp-al-ext' );
load_textdomain( 'mwp-al-ext', WP_LANG_DIR . '/mwp-al-ext/mwp-al-ext-' . $locale . '.mo' );
load_plugin_textdomain( 'mwp-al-ext', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
}
/**
* Load extension on `plugins_loaded` action.
*/
public function load_mwpal_extension() {
// create background processes in order to register their hooks
new Enforce_Settings_Update_Process();
new Enforce_Settings_Removal_Process();
}
/**
* DB connection.
*
* @param mixed $config - DB configuration.
* @param bool $reset - True if reset.
* @return \WSAL\MainWPExtension\Connector\ConnectorInterface
*/
public static function get_connector( $config = null, $reset = false ) {
return \WSAL\MainWPExtension\Connector\ConnectorFactory::getConnector( $config, $reset );
}
/**
* Save option that extension has been activated.
*/
public function install_extension() {
if ( ! is_plugin_active( 'mainwp/mainwp.php' ) ) {
?>
!
' . esc_html__( 'Getting Started Guide', 'mwp-al-ext' ) . ''
);
?>
settings ) ) {
$this->settings = new \WSAL\MainWPExtension\Settings();
}
// Ensure that the system is installed and schema is correct.
self::get_connector()->installAll();
// Option to redirect to extensions page.
$this->settings->set_extension_activated( 'yes' );
$new_version = $this->mwp_current_plugin_version();
$old_version = $this->mwp_old_plugin_version();
// If compare old version and new version
if ( $old_version !== $new_version ) {
mwpal_extension()->settings->update_option( 'version', $new_version );
delete_transient( 'mwpal-is-advert-dismissed' );
}
// Install refresh hook (remove older one if it exists).
wp_clear_scheduled_hook( 'mwp_events_cleanup' );
wp_schedule_event( current_time( 'timestamp' ) + 600, 'hourly', 'mwp_events_cleanup' );
}
/**
* The current plugin version (according to plugin file metadata).
*
* @return string
*/
public function mwp_current_plugin_version() {
$version = get_plugin_data( __FILE__, false, false );
return isset( $version['Version'] ) ? $version['Version'] : '0.0.0';
}
/**
* The plugin version as stored in DB (will be the old version during an update/install).
*
* @return string
*/
public function mwp_old_plugin_version() {
return mwpal_extension()->settings->get_option( 'version', '0.0.0' );
}
/**
* Define constants.
*/
public function define_constants() {
// Plugin version.
if ( ! defined( 'MWPAL_VERSION' ) ) {
define( 'MWPAL_VERSION', $this->version );
}
// Plugin Name.
if ( ! defined( 'MWPAL_BASE_NAME' ) ) {
define( 'MWPAL_BASE_NAME', plugin_basename( __FILE__ ) );
}
// Plugin Directory URL.
if ( ! defined( 'MWPAL_BASE_URL' ) ) {
define( 'MWPAL_BASE_URL', plugin_dir_url( __FILE__ ) );
}
// Plugin Directory Path.
if ( ! defined( 'MWPAL_BASE_DIR' ) ) {
define( 'MWPAL_BASE_DIR', plugin_dir_path( __FILE__ ) );
}
// Plugin Extension Name.
if ( ! defined( 'MWPAL_EXTENSION_NAME' ) ) {
$filename = preg_replace( '#\/[^/]*$#', '', MWPAL_BASE_NAME );
$filename = str_replace( '-', ' ', $filename );
$filename = ucwords( $filename );
$filename = str_replace( ' ', '-', $filename );
define( 'MWPAL_EXTENSION_NAME', 'Extensions-' . $filename );
}
// Plugin Min PHP Version.
if ( ! defined( 'MWPAL_MIN_PHP_VERSION' ) ) {
define( 'MWPAL_MIN_PHP_VERSION', '5.5.0' );
}
// Plugin Options Prefix.
if ( ! defined( 'MWPAL_OPT_PREFIX' ) ) {
define( 'MWPAL_OPT_PREFIX', 'mwpal-' );
}
// Plugin uploads directory path.
if ( ! defined( 'MWPAL_UPLOADS_DIR' ) ) {
$uploads_dir = wp_upload_dir();
define( 'MWPAL_UPLOADS_DIR', trailingslashit( $uploads_dir['basedir'] ) . 'activity-log-for-mainwp/' );
}
}
/**
* Redirect to MainWP Extensions Page.
*
* @return void
*/
public function redirect_on_activate() {
$redirect_url = false;
if ( 'yes' === $this->settings->is_extension_activated() ) {
// clear the activation flag so this runs only once.
$this->settings->delete_option( 'activity-extension-activated' );
if ( ! $this->settings->get_option( 'setup-complete' ) ) {
$redirect_url = add_query_arg( 'page', 'activity-log-mainwp-setup', admin_url( 'admin.php' ) );
} else {
$redirect_url = add_query_arg( 'page', MWPAL_EXTENSION_NAME, admin_url( 'admin.php' ) );
}
}
if ( $redirect_url ) {
wp_safe_redirect( $redirect_url );
exit();
}
}
/**
* Add extension to MainWP.
*
* @param array $plugins – Array of plugins.
* @return array
*/
public function get_this_extension( $plugins ) {
$plugins[] = array(
'plugin' => __FILE__,
'api' => basename( __FILE__, '.php' ),
'mainwp' => false,
'callback' => array( &$this, 'display_extension' ),
'icon' => trailingslashit( MWPAL_BASE_URL ) . 'assets/img/activity-log-mainwp-500x500.jpg',
);
return $plugins;
}
/**
* Extension Display on MainWP Dashboard.
*/
public function display_extension() {
$this->extension_view->render_page();
}
/**
* The function "activate_this_plugin" is called when the main is initialized.
*/
public function activate_this_plugin() {
// Checking if the MainWP plugin is enabled. This filter will return true if the main plugin is activated.
$this->mainwp_main_activated = apply_filters( 'mainwp_activated_check', $this->mainwp_main_activated );
// The 'mainwp_extension_enabled_check' hook. If the plugin is not enabled this will return false,
// if the plugin is enabled, an array will be returned containing a key.
// This key is used for some data requests to our main.
$this->child_enabled = apply_filters( 'mainwp_extension_enabled_check', __FILE__ );
$this->child_key = $this->child_enabled['key'];
}
/**
* MainWP Plugin Error Notice.
*/
public function mainwp_error_notice() {
global $current_screen;
if ( 'plugins' === $current_screen->parent_base && false === $this->mainwp_main_activated ) {
/* Translators: MainWP website hyperlink */
echo '' . sprintf( esc_html__( 'Activity Log for MainWP Extension requires %1$s plugin to be activated in order to work. Please install and activate %2$s first.', 'mwp-al-ext' ), 'MainWP', 'MainWP' ) . '
';
}
}
/**
* MainWP Plugin Error Notice.
*/
public function mainwp_merged_notice() {
global $current_screen;
/* Translators: MainWP website hyperlink */
echo '' . sprintf( esc_html__( 'The Activity Log for MainWP extension is being merged in WP Activity Log 5.0, which is to be released in the upcoming days. Please %1$s before upgrading.', 'mwp-al-ext' ), 'read this' ) . '
';
}
/**
* Check if extension is enabled.
*
* @return boolean
*/
public function is_child_enabled() {
return $this->child_enabled;
}
/**
* Get Child Key.
*
* @return string
*/
public function get_child_key() {
return $this->child_key;
}
/**
* Get Child File.
*
* @return string
*/
public function get_child_file() {
return $this->child_file;
}
/**
* Load events from external files. Extension specific events are loaded from `default-events.php`. Definitions of
* events pulled from child sites are syncing automatically since version 2.0.0 and stored in file
* `dynamic-events.php`. This file is also loaded here if available.
*/
public function load_events() {
require_once MWPAL_BASE_DIR . 'default-events.php';
if ( file_exists( MWPAL_BASE_DIR . 'dynamic-events.php' ) ) {
require_once MWPAL_BASE_DIR . 'dynamic-events.php';
}
}
/**
* Error Logger
*
* Logs given input into debug.log file in debug mode.
*
* @param mix $message - Error message.
*/
public function log( $message ) {
if ( WP_DEBUG === true ) {
if ( is_array( $message ) || is_object( $message ) ) {
error_log( print_r( $message, true ) );
} else {
error_log( $message );
}
}
}
/**
* Clean Up Events
*
* Clean up events of a site if the latest event is more
* than three hours late.
*/
public function events_cleanup() {
// Get MainWP sites.
$child_sites = $this->settings->get_wsal_child_sites();
$server_ip = $this->settings->get_server_ip(); // Get server IP.
if ( ! empty( $child_sites ) && is_array( $child_sites ) ) {
$sites_data = array();
$trigger_retrieving = true; // Event 7711.
$trigger_ready = true; // Event 7712.
foreach ( $child_sites as $site_id => $site ) {
$event = $this->get_latest_event_by_siteid( $site_id );
$hrs_diff = 0;
if ( $event ) {
$hrs_diff = $this->settings->get_hours_since_last_alert( $event->created_on );
}
// If the hours difference is less than the selected frequency then skip this site.
if ( 0 !== $hrs_diff && $hrs_diff < $this->settings->get_events_frequency() ) {
continue;
}
// Get latest event from child site.
$live_event = $this->get_live_event_by_siteid( $site_id );
// If the latest event on the dashboard matches the timestamp of the latest event on child site, then skip.
if ( isset( $event->created_on ) && isset( $live_event->created_on ) && $event->created_on === $live_event->created_on ) {
continue;
}
// Delete events by site id.
$this->alerts->delete_site_events( $site_id );
// Fetch events by site id.
$sites_data[ $site_id ] = $this->alerts->fetch_site_events( $site_id, $trigger_retrieving );
// Set $trigger_retrieving to false to avoid logging 7711 multiple times.
$trigger_retrieving = false;
if ( $trigger_ready && isset( $sites_data[ $site_id ]->events ) ) {
// Extension is ready after retrieving.
$this->alerts->trigger(
7712,
array(
'mainwp_dash' => true,
'Username' => 'System',
'ClientIP' => ! empty( $server_ip ) ? $server_ip : false,
)
);
$trigger_ready = false;
}
}
// Set child site events.
$this->alerts->set_site_events( $sites_data );
}
foreach ( $this->cleanup_hooks as $hook ) {
call_user_func( $hook );
}
}
/**
* Get the latest event by site id.
*
* @param integer $site_id — Site ID.
* @return array
*/
private function get_latest_event_by_siteid( $site_id = 0 ) {
// Return if site id is empty.
if ( empty( $site_id ) ) {
return false;
}
// Query for latest event.
$event_query = new \WSAL\MainWPExtension\Models\OccurrenceQuery();
$event_query->addCondition( 'site_id = %s ', $site_id ); // Set site id.
$event_query->addOrderBy( 'created_on', true );
$event_query->setLimit( 1 );
$event = $event_query->getAdapter()->Execute( $event_query );
if ( isset( $event[0] ) ) {
// Event is found.
return $event[0];
} else {
// Check the last checked timestamp against this site id.
$last_checked = $this->settings->get_last_checked_by_siteid( $site_id );
if ( ! $last_checked ) {
$next_update = time() + ( $this->settings->get_events_frequency() * 60 * 60 ) + 1;
$this->settings->set_last_checked_by_siteid( $next_update, $site_id );
} else {
$last_event = new \stdClass();
$last_event->created_on = $last_checked;
return $last_event;
}
}
return false;
}
/**
* Get live event by site id (from child site).
*
* @param integer $site_id — Site ID.
*
* @return stdClass|false
*/
private function get_live_event_by_siteid( $site_id = 0 ) {
return $this->make_api_call( $site_id, 'latest_event' );
}
/**
* Makes an API call to a child site.
*
* @param int $site_id Site ID.
* @param string $action Action attribute.
* @param array $extra_data Extra arguments.
*
* @return false|stdClass
*
* @since 2.0.0
*/
public function make_api_call( $site_id, $action, $extra_data = array() ) {
// Return if site id is empty.
if ( empty( $site_id ) ) {
return false;
}
// Post data for child sites.
$post_data = array(
'action' => $action,
);
if ( is_array( $extra_data ) && ! empty( $extra_data ) ) {
$post_data = array_merge( $post_data, $extra_data );
}
// Call the child site.
return apply_filters(
'mainwp_fetchurlauthed',
$this->get_child_file(),
$this->get_child_key(),
$site_id,
'extra_excution',
$post_data
);
}
/**
* Add Plugin Shortcut Links.
*
* @since 1.0.3
*
* @param array $old_links - Old links.
* @return array
*/
public function add_plugin_page_links( $old_links ) {
// Extension view URL.
$extension_url = add_query_arg( 'page', MWPAL_EXTENSION_NAME, admin_url( 'admin.php' ) );
// New plugin links.
$new_links = array(
'mwpal-view' => '' . __( 'View Activity Log', 'mwp-al-ext' ) . '',
'mwpal-settings' => '' . __( 'Settings', 'mwp-al-ext' ) . '',
);
return array_merge( $new_links, $old_links );
}
/**
* Add callback to be called when a cleanup operation is required.
*
* @param callable $hook - Hook name.
*/
public function add_cleanup_hook( $hook ) {
$this->cleanup_hooks[] = $hook;
}
/**
* Checks if MainWP dashboard plugin is active or not.
*
* @return boolean
*/
public function is_mainwp_active() {
return $this->mainwp_main_activated;
}
/**
* When MainWP site is deleted this removes it from the list of ALMWP's
* list of sites so we don't try fetch it when it doesn't exists.
*
* @method remove_almwp_child_when_removed_from_mwp
* @since 1.3.0
* @param stdObject $site object containing site data that has been removed.
*/
public function remove_almwp_child_when_removed_from_mwp( $site ) {
$wsal_child_sites = $this->settings->get_wsal_child_sites(); // Get activity log sites.
if ( isset( $wsal_child_sites[ $site->id ] ) ) {
// remove the site from the array.
unset( $wsal_child_sites[ $site->id ] );
// update the child sites with keys from the sites.
$this->settings->set_wsal_child_sites( array_keys( $wsal_child_sites ) );
}
}
/**
* Sets a custom page title for our extension plugin.
*
* @param string $title Page title.
*
* @return string
*/
public function custom_page_title( $title ) {
if ( isset( $_REQUEST['page'] ) && 'Extensions-Activity-Log-Mainwp-Premium' === $_REQUEST['page'] || isset( $_REQUEST['page'] ) && 'Extensions-Activity-Log-Mainwp' === $_REQUEST['page'] ) {
$title = esc_html__( 'Activity Log for MainWP', 'mwp-al-ext' );
}
return $title;
}
/**
* Runs when a new MainWP site is added. If the site is running WSAL plugin, it is added to list of ALMWP's list of
* sites.
*
* @param int $id Child site ID.
*
* @since 2.0.0
*/
public function add_almwp_child_when_added_to_mwp( $id ) {
if ( ! $this->settings->can_automatically_add_new_sites() ) {
// Automatic addition of new sites is disabled in plugin settings.
return;
}
$website = \MainWP_DB::instance()->getWebsiteById( $id );
if ( is_null( $website ) ) {
return;
}
$wsal_child_sites = $this->settings->get_wsal_child_sites();
if ( isset( $wsal_child_sites[ $id ] ) ) {
/*
* Stop here if the site is already in the list. This would only happen in some edge cases, if the site was
* removed from MainWP and re-added later,
*/
return;
}
$response = View::check_if_wsal_installed_on_site( $id );
if ( false !== $response ) {
// WSAL is installed, add the site to the list.
$new_list = array_keys( $wsal_child_sites );
$new_list[] = $id;
$this->settings->set_wsal_child_sites( $new_list );
}
}
/**
* Updates the dynamic event definitions by making an APIr call to retrieve the latest definitions from the child
* site.
*
* @param int $site_id Child site ID.
*
* @since 2.0.0
*/
public function update_dynamic_event_definitions( $site_id ) {
$definitions = $this->make_api_call( $site_id, 'get_event_definitions' );
if ( ! is_array( $definitions ) || ! array_key_exists( 'events', $definitions ) ) {
// Child site does not support this API call (only available since WSAL 4.4.0) or the communication failed.
return;
}
// Load the existing JSON file and merge with given data.
$existing_data = array();
$json_file = MWPAL_BASE_DIR . 'dynamic-events.json';
if ( file_exists( $json_file ) ) {
$existing_data = json_decode( file_get_contents( $json_file ), true );
foreach ( array( 'events', 'objects', 'types' ) as $item_type ) {
foreach ( $definitions[ $item_type ] as $key => $value ) {
if ( ! array_key_exists( $key, $existing_data[ $item_type ] ) ) {
$existing_data[ $item_type ][ $key ] = $value;
}
}
}
} else {
$existing_data = $definitions;
}
file_put_contents( $json_file, json_encode( $existing_data ) );
$existing_data['events'] = $this->get_categorized_events( $existing_data['events'] );
EventDefinitionsWriter::write_definitions( $existing_data, MWPAL_BASE_DIR . 'dynamic-events.php' );
}
/**
* Organizes given events into a category/subcategory structured array.
*
* @param array $raw_events Raw flat list of events.
*
* @return array Categorized events.
* @since 2.0.0
*/
public function get_categorized_events( $raw_events ) {
$result = array();
foreach ( $raw_events as $raw_event ) {
if ( ! isset( $result[ $raw_event['catg'] ] ) ) {
$result[ $raw_event['catg'] ] = array();
}
if ( ! isset( $result[ $raw_event['catg'] ][ $raw_event['subcatg'] ] ) ) {
$result[ $raw_event['catg'] ][ $raw_event['subcatg'] ] = array();
}
$result[ $raw_event['catg'] ][ $raw_event['subcatg'] ][] = $raw_event;
}
return $result;
}
}
/**
* Return the one and only instance of this plugin.
*
* @return \WSAL\MainWPExtension\Activity_Log
*/
function mwpal_extension() {
return \WSAL\MainWPExtension\Activity_Log::get_instance();
}
// Initiate the plugin.
mwpal_extension();