get_website_options_array( $site_id, array( 'changes_logs_sync_last_created' ) ); if ( ! is_array( $site_opts ) ) { $site_opts = array(); } static::$last_log_created[ $site_id ] = isset( $site_opts['changes_logs_sync_last_created'] ) ? $site_opts['changes_logs_sync_last_created'] : 0; // to sure. if ( empty( static::$last_log_created[ $site_id ] ) ) { static::$last_log_created[ $site_id ] = time() - DAY_IN_SECONDS; // to prevent "strange" issue. MainWP_DB::instance()->update_website_option( $site_id, 'changes_logs_sync_last_created', static::$last_log_created[ $site_id ] ); } } return static::$last_log_created[ $site_id ]; } /** * Method sync_changes_logs(). * * Sync site changes logs data. * * @param int $site_id site id. * @param array $sync_changes action data. * @param object $website website data. * * @return bool */ public function sync_changes_logs( $site_id, $sync_changes, $website ) { // phpcs:ignore -- NOSONAR - complex. MainWP_Logger::instance()->log_events( 'sites-changes', 'Sync changes logs :: [site_id=' . $site_id . '] :: [count=' . ( is_array( $sync_changes ) ? count( $sync_changes ) : 0 ) . ']' ); if ( empty( $sync_changes ) || ! is_array( $sync_changes ) ) { return false; } $sync_last_created = $this->get_sync_changes_logs_last_created( $site_id ); $new_last_created = 0; $disabled_type_last_created = 0; $created_success = false; $ignored_meta_fields = apply_filters( 'mainwp_module_log_sync_ignored_meta_fields', array( 'userdata', 'user_meta' ) ); if ( ! is_array( $ignored_meta_fields ) ) { $ignored_meta_fields = array(); } foreach ( $sync_changes as $data ) { if ( ! is_array( $data ) || empty( $data['created_on'] ) || empty( $data['log_type_id'] ) ) { continue; } $item_created = round( (float) $data['created_on'], 4 ); // to fix float comparing issue. if ( $item_created <= $sync_last_created ) { continue; } // to fix issue of last sync value. if ( $new_last_created < $item_created ) { $new_last_created = $item_created; } $enable_log_type = apply_filters( 'mainwp_module_log_enable_insert_log_type', true, $data ); if ( ! $enable_log_type ) { // to fix issue of last sync value. if ( $disabled_type_last_created < $item_created ) { $disabled_type_last_created = $item_created; } continue; } $type_id = intval( $data['log_type_id'] ); $user_id = ! empty( $data['user_id'] ) ? sanitize_text_field( $data['user_id'] ) : 0; $user_login = ! empty( $data['username'] ) ? sanitize_text_field( $data['username'] ) : ''; if ( empty( $user_login ) ) { continue; } $meta_data = isset( $data['meta_data'] ) && is_array( $data['meta_data'] ) ? $data['meta_data'] : array(); $user_meta = isset( $meta_data['user_meta'] ) && is_array( $meta_data['user_meta'] ) ? $meta_data['user_meta'] : array(); $meta = array(); $meta['user_meta_json'] = wp_json_encode( $user_meta ); $meta['client_ip'] = $data['client_ip']; if ( is_array( $meta_data ) ) { foreach ( $meta_data as $key => $val ) { if ( in_array( $key, $ignored_meta_fields ) ) { continue; } $meta[ $key ] = $val; } } $action = isset( $data['action_name'] ) ? $this->map_changes_action( $data['action_name'] ) : ''; $context = ''; if ( isset( $data['context'] ) ) { $context = $this->map_change_logs_context( $data['context'] ); } elseif ( isset( $data['log_type_id'] ) ) { $context = $this->map_change_logs_context( '', $data['log_type_id'] ); } $duration = isset( $data['duration'] ) ? sanitize_text_field( $data['duration'] ) : 0; // sanitize_text_field for seconds. $created = isset( $data['created_on'] ) ? (float) ( $data['created_on'] ) : microtime( true ); $record_mapping = array( 'site_id' => $site_id, 'user_id' => $user_id, 'user_login' => $user_login, 'created' => $created, 'context' => $context, 'action' => $action, 'state' => 1, 'duration' => $duration, 'meta' => $meta, 'log_type_id' => $type_id, ); $sum = 'wordpress' !== $record_mapping['context'] ? esc_html( ucfirst( rtrim( $record_mapping['context'], 's' ) ) ) : 'WordPress'; //phpcs:ignore -- wordpress text. $record_mapping['item'] = $sum; $inserted_id = apply_filters( 'mainwp_sync_site_log_changes_logs', false, $website, $record_mapping ); if ( $inserted_id ) { $created_success = true; } } // to fix last created sync. $update_sync_last_created = 0; if ( $new_last_created && $created_success ) { $update_sync_last_created = $new_last_created; } if ( $disabled_type_last_created && $update_sync_last_created < $disabled_type_last_created ) { $update_sync_last_created = $disabled_type_last_created; } if ( ! empty( $update_sync_last_created ) ) { MainWP_DB::instance()->update_website_option( $site_id, 'changes_logs_sync_last_created', $update_sync_last_created ); } return true; } /** * Method map_changes_action. * * @param string $event Logs event. * * @return string Dashboard logs actions to store in db. */ public function map_changes_action( $event ) { $map_actions = array( 'installed' => 'install', 'deleted' => 'delete', 'activated' => 'activate', 'deactivated' => 'deactivate', ); return isset( $map_actions[ $event ] ) ? $map_actions[ $event ] : $event; } /** * Method map_change_logs_context() * * @param string $context Log context|object. * @param int $type_id Logs type code. * * @return string Dashboard logs context to store in db. */ public function map_change_logs_context( $context, $type_id = 0 ) { if ( ! empty( $type_id ) ) { $context = isset( static::get_changes_logs_types( $type_id )['context'] ) ? static::get_changes_logs_types( $type_id )['context'] : ''; } $context = 'cron-job' === $context ? 'cron' : $context; return \apply_filters( 'mainwp_module_log_changes_logs_mapping_contexts', $context, $type_id ); } /** * Get custom event title. * * @param int $log_type_id - Event type id. * @param array $data - Event data. * @param string $type - Title type. * * @return string */ public static function get_changes_log_title( $log_type_id, $data, $type ) { // phpcs:ignore -- NOSONAR - complex. if ( ! is_array( $data ) ) { $data = array(); } $title = ''; if ( 'action' === $type ) { if ( 1965 === (int) $log_type_id ) { $title = isset( static::get_changes_logs_types( $log_type_id )['action_name'] ) ? static::get_changes_logs_types( $log_type_id )['action_name'] : ''; if ( ! empty( $title ) ) { $title = ucfirst( $title ); } } else { $title = isset( static::get_changes_logs_types( $log_type_id )['msg'] ) ? static::get_changes_logs_types( $log_type_id )['msg'] : ''; } } elseif ( 'object' === $type ) { $title = isset( static::get_changes_logs_types( $log_type_id )['object_msg'] ) ? static::get_changes_logs_types( $log_type_id )['object_msg'] : ''; } if ( ! empty( $title ) ) { if ( isset( $data['action'] ) ) { $title = str_replace( '%action%', $data['action'], $title ); } if ( isset( $data['plugin'] ) ) { $title = str_replace( '%plugin%', $data['plugin'], $title ); } if ( isset( $data['theme'] ) ) { $title = str_replace( '%theme%', $data['theme'], $title ); } if ( isset( $data['name'] ) ) { $title = str_replace( '%name%', $data['name'], $title ); } return $title; } return ''; } /** * Method get_changes_logs_types(). * * @param int $type_id Logs type code. * * @return array data. */ public static function get_changes_logs_types( $type_id = null ) { //phpcs:ignore -- NOSONAR - long function. static $defaults; if ( null === $defaults ) { $defaults = include MAINWP_MODULES_DIR . 'logs/includes/default-logs.php'; //phpcs:ignore -- NOSONAR ok. } if ( ! is_array( $defaults ) ) { $defaults = array(); } if ( null !== $type_id ) { return is_scalar( $type_id ) && isset( $defaults[ $type_id ] ) ? $defaults[ $type_id ] : array(); } return $defaults; } /** * Method get_changes_logs_object_title(). * * @param object $item Logs type code. * @param string $default_title Default title. * * @return strinng Object title. */ public static function get_changes_logs_object_title( $item = null, $default_title = '' ) { //phpcs:ignore -- NOSONAR - long function. $title = ''; if ( ! empty( $item->log_type_id ) ) { $meta = isset( $item->meta ) && is_array( $item->meta ) ? $item->meta : array(); if ( 'system-setting' === $item->context ) { $title = isset( self::get_changes_logs_types( $item->log_type_id )['title'] ) ? self::get_changes_logs_types( $item->log_type_id )['title'] : ''; if ( empty( $title ) ) { $title = esc_html__( 'System Setting', 'mainwp' ); } } elseif ( 'database' === $item->context ) { if ( ! empty( $meta['tablenames'] ) ) { $title = is_array( $meta['tablenames'] ) ? implode( ', ', $meta['tablenames'] ) : esc_html( $meta['tablenames'] ); $title = esc_html( $title ); } if ( empty( $title ) ) { $title = esc_html__( 'Database Table', 'mainwp' ); } } elseif ( ( 1970 === (int) $item->log_type_id || 1980 === (int) $item->log_type_id ) ) { if ( ! empty( $meta['name'] ) && is_scalar( $meta['name'] ) ) { $title = esc_html( $meta['name'] ); } elseif ( empty( $default_title ) ) { $title = 1970 === (int) $item->log_type_id ? esc_html__( 'Plugin', 'mainwp' ) : esc_html__( 'Theme', 'mainwp' ); } } } return ! empty( $title ) ? $title : $default_title; } /** * Method get_history_changes(). * * @param array $args Arguments. * * @return array Results. */ public function get_history_changes( $args ) { // phpcs:ignore -- NOSONAR - complex. if ( ! is_array( $args ) ) { $args = array(); } $results = Log_DB_Helper::instance()->get_changes_logs_by( $args ); if ( ! is_array( $results ) ) { $results = array(); } $lists = array(); $manager = Log_Manager::instance(); $index_by_date = ! empty( $args['target_date'] ) ? 'name' : 'date'; $get_name = ! empty( $args['slug'] ) || ! empty( $args['name'] ); $name_title = ''; $tbl_list = new Log_Events_List_Table( $manager ); if ( ! empty( $results['items'] ) ) { foreach ( $results['items'] as $item ) { if ( empty( $item->log_id ) ) { continue; } $created_micro = (int) $item->created; $record = new Log_Record( $item ); $created_sec = (int) $record->created; $details = array( 'author_name' => $tbl_list->get_log_author_name( $record ), 'source' => 'non-mainwp-changes' === $record->connector ? 'WP Admin' : 'Dashboard', 'at_hour' => MainWP_Utility::format_time( $created_sec ), 'connector' => $record->connector, 'context' => $record->context, 'action' => $record->action, 'event' => $tbl_list->get_event_title( $record, 'action' ), 'log_id' => $item->log_id, ); $slugidx = ''; $slug = ''; $name_meta = ''; if ( ! empty( $record->meta ) && is_array( $record->meta ) ) { $slug = ! empty( $record->meta['slug'] ) ? $record->meta['slug'] : ''; $name_meta = ! empty( $record->meta['name'] ) ? $record->meta['name'] : ''; } if ( empty( $slug ) && ! empty( $record->extra_meta ) ) { $extra_data = json_decode( $record->extra_meta, true ); if ( is_array( $extra_data ) && ! empty( $extra_data['slug'] ) ) { $slug = $extra_data['slug']; } } if ( ! empty( $slug ) ) { if ( false !== strpos( $slug, '/' ) ) { $parts = explode( '/', $slug ); $slugidx = $parts[0]; } else { $slugidx = basename( $slug, '.php' ); } $slugidx = strtolower( $slugidx ); } elseif ( ! empty( $name_meta ) ) { $slugidx = strtolower( sanitize_title( $name_meta ) ); } if ( empty( $slugidx ) && ! empty( $record->item ) ) { $slugidx = strtolower( sanitize_title( $record->item ) ); } if ( 'date' === $index_by_date ) { $day = MainWP_Utility::get_local_date_by_utc_timestamp( $created_micro / 1000000 ); // float. if ( ! isset( $lists[ $day ] ) ) { $lists[ $day ] = array(); } $list_item = array( 'date' => MainWP_Utility::format_date( $created_sec ), 'details' => $details, ); if ( $get_name && empty( $name_title ) ) { $name_title = $tbl_list->get_object_title( $record, false, false ); } if ( 'updated' === $record->action || 'update' === $record->action ) { if ( ! empty( $record->extra_meta ) ) { $meta = json_decode( $record->extra_meta, true ); } else { $meta = $record->meta; } if ( ! is_array( $meta ) ) { $meta = array(); } if ( ! empty( $meta['version'] ) ) { $list_item['details']['version'] = $meta['version']; } if ( ! empty( $meta['old_version'] ) ) { $list_item['details']['old_version'] = $meta['old_version']; } } $lists[ $day ][] = $list_item; } else { // group by plugin/theme name. $group_key = $slugidx . '_' . $record->site_id; if ( ! isset( $lists[ $group_key ] ) ) { $lists[ $group_key ] = array(); } $list_item = array( 'name' => $tbl_list->get_object_title( $record ), 'site_id' => $record->site_id, 'item_name' => $name_meta, 'item_slug' => $slug, 'details' => $details, ); if ( 'updated' === $record->action || 'update' === $record->action ) { if ( ! empty( $record->extra_meta ) ) { $meta = json_decode( $record->extra_meta, true ); } else { $meta = $record->meta; } if ( ! is_array( $meta ) ) { $meta = array(); } if ( ! empty( $meta['version'] ) ) { $list_item['details']['version'] = $meta['version']; } if ( ! empty( $meta['old_version'] ) ) { $list_item['details']['old_version'] = $meta['old_version']; } } $lists[ $group_key ][] = $list_item; } } } $resp = array( 'list' => $lists, ); if ( ! empty( $results['onward_time'] ) ) { $resp['onward_date'] = MainWP_Utility::format_timezone( $results['onward_time'] ); } if ( ! empty( $name_title ) ) { $resp['name_title'] = $name_title; } return $resp; } }